如何定义通用扩展方法

时间:2013-07-15 22:09:48

标签: c#

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

期望使用: 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>();

4 个答案:

答案 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)

(使用此界面,您甚至不需要知道真实类型是什么;如果您这样做,请使用asis)或甚至:

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);

答案 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.
}