9

我正在尝试定义一个扩展方法,该方法可以返回调用定义的类型的对象。

预期用途: Cat acat = guy.GiveMeYourPet<Cat>();

尝试实施

我可以毫不费力地定义这样的泛型方法:

public static T GiveMeYourPet<T>(Person a) { ... }

Cat acat = GiveMeYourPet<Cat>(guy);

或像这样的扩展方法:

public static Cat GiveMeYourPetCat<P>(this P self) where P : Person, ... { ... }

Cat acat = guy.GiveMeYourPetCat();

但是当我尝试做我真正想做的事情时:

public static T GiveMeYourPet<T, P>(this P self) where P : Person, ... { ... }

Cat acat = guy.GiveMeYourPet<Cat>();

编译器期望 GiveMeYourPet() 接收 2 个类型参数(即使一个是通过调用 object 的扩展方法隐式提供的guy

我能做些什么来完成这项工作?

请注意,我还尝试颠倒定义参数的顺序,但没有任何变化:

public static T GiveMeYourPet<P, T>(this P self)

以下调用也不起作用,因为您不能在类型规范中进行方法调用:

Cat acat = guy.GiveMeYourPet<guy.GetType(), Cat>();
4

4 回答 4

5

C# 编译器类型推断并不像您希望的那样复杂。您必须在这样的方法中明确指定这两种类型:

void Main()
{
    int i = 0;
    bool b = i.GiveMeYourPet<bool, int>();
}

public static class MyExtensions
{
    public static T GiveMeYourPet<T, P>(this P self)
    {
        return default(T);
    }
}

如果您想避免明确指定两者(我不会责怪您),您可以尝试将您的方法更改为:

public static T GiveMeYourPet<T>(this IPetOwner self)

(使用此接口,您甚至不需要知道真正的类型是什么;如果您知道,请使用asor is)甚至:

public static T GiveMeYourPet<T>(this object self)

(并使用asis

如果这不是一个选项,并且guy(在您的示例中)的真实类型不是静态已知的(例如,您只是将他作为object),您可能必须使用反射,例如:

MethodInfo method = typeof(MyExtensions).GetMethod("GiveMeYourPet");
MethodInfo generic = method.MakeGenericMethod(typeof(Pet), guy.GetType());
generic.Invoke(guy, null);
于 2013-07-15T22:14:25.700 回答
1

如果类似的东西guy.GiveMeYour.Pet<Cat>();可以工作,您可以构建类似于代码的 2 个级别:

public class GiveMeYourBuilder<P>
{
   public P Me {get;set;}
   public T Pet<T>() : where T: new()
   { return new T();}
}

public static PetExtensions 
{
    public GiveMeYourBuilder<P>(this P me)
    {
         return new GiveMeYourBuilder<P> { Me = me;}
    }
}
于 2013-07-15T22:20:11.393 回答
1

您不能部分指定泛型参数,要么它们都是推断出来的,要么你必须全部指定它们。在这种情况下,您可以获得的最接近的可能是返回一个中间对象,该对象带有Person调用扩展方法的泛型类型,并在其上定义您的Get方法:

public class GiveContext<T> where T : Person
{
    public P MeYourPet<P>() where P : Pet
    {
        return default(P);
    }
}

public static GiveContext<T> Give<T>(this T person) where T : Person
{
    return new GiveContext<T>();
}

你可以像这样使用:

var p = new Person();
Cat c = p.Give().MeYourPet<Cat>();
于 2013-07-15T22:21:15.607 回答
0

不幸的是,你不能这样做。如果编译器无法全部计算出来,则需要输入所有类型参数。C# 编译器并不那么聪明。dynamic不过可以提供帮助:

public static T GiveMeYourPet<T>(this dynamic self)
{
    //in here check that self meets your constraints using is, as, etc.
}
于 2013-07-15T22:21:25.070 回答