我正在尝试定义一个扩展方法,该方法可以返回由调用定义的类型的对象。
期望使用: 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个类型的参数(即使通过调用对象guy
上的扩展方法隐式提供了一个参数。
我可以做些什么来完成这项工作?
请注意,我也尝试颠倒定义参数的顺序,但没有任何变化:
public static T GiveMeYourPet<P, T>(this P self)
以下调用也不起作用,因为您无法在类型说明中进行方法调用:
Cat acat = guy.GiveMeYourPet<guy.GetType(), Cat>();
答案 0 :(得分: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)
(使用此界面,您甚至不需要知道真实类型是什么;如果您这样做,请使用as
或is
)或甚至:
public static T GiveMeYourPet<T>(this object self)
(并使用as
或is
)
如果那不是一个选项,并且guy
(在你的例子中)的真实类型不是静态知道的(例如你只是将他作为object
),你可能不得不使用反思,例如:
MethodInfo method = typeof(MyExtensions).GetMethod("GiveMeYourPet");
MethodInfo generic = method.MakeGenericMethod(typeof(Pet), guy.GetType());
generic.Invoke(guy, null);
答案 1 :(得分: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;}
}
}
答案 2 :(得分: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>();
答案 3 :(得分:0)
不幸的是,你无法做到这一点。如果编译器无法将它们计算为 all ,则需要键入所有类型参数。 C#编译器不是 智能。 dynamic
可以提供帮助:
public static T GiveMeYourPet<T>(this dynamic self)
{
//in here check that self meets your constraints using is, as, etc.
}