泛型函数创建参数base的泛型对象

时间:2014-05-02 12:02:14

标签: c# generics inheritance

我有以下代码:

public class Foo
{
    public void DoSomething()
    {
        DoSomething(this);
    }

    private static void DoSomething<T>(T obj)
    {
        var generic = new Generic<T>();
    }
}

public class Bar : Foo
{
    // properties/methods
}

public class Generic<T>
{
    // properties/methods
}

public class Test
{
    public void TestMethod()
    {
        var bar = new Bar();
        bar.DoSomething(); // instantiates Generic<Foo> instead of Generic<Bar>
    }
}

是否可以使用当前类型而不是基类型从派生方法实例化泛型类?

2 个答案:

答案 0 :(得分:5)

thisFoo.DoSomething的编译时类型只是Foo,因此编译器只能 将类型参数推断为Foo

根据执行时间类型获取它的最简单方法可能是:

DoSomething((dynamic) this);

或者,您可以自己用反射来调用它。

答案 1 :(得分:3)

问题是它正在将T解析为您调用方法的编译时类型。在这种情况下,它在Foo.Something内被调用/解析,编译时类型thisFoo,而不是Bar

一种选择是拨打电话virtual并让每种类型override。这将使每次调用方法时都提供编译时类型信息:

public class Foo
{
    public virtual void DoSomething()
    {
        DoSomething(this);
    }

    //notice this is protected now so it's accessible to `Bar`
    protected static void DoSomething<T>(T obj)
    {
        var generic = new Generic<T>();
    }
}

public class Bar : Foo
{
    public override void DoSomething()
    {
        DoSomething(this);
    }
}

另一种选择是使用动态语言运行时使其在运行时解析类型:

public class Foo
{
    public void DoSomething()
    {
        dynamic thisDynamic = this;
        DoSomething(thisDynamic);
    }

    private static void DoSomething<T>(T obj)
    {
        var generic = new Generic<T>();
    }
}

编辑:如果您没有使用.NET 4.0并且无法访问动态语言运行时,您也可以使用泛型:

public class Foo
{
    public void DoSomething()
    {
        DoSomething(this);
    }

    private static void DoSomething(object obj)
    {
        Type runtimeType = obj.GetType();
        MethodInfo createMethod = typeof(Foo).GetMethod("CreateGeneric", BindingFlags.Static | BindingFlags.NonPublic);
        var genericCreateMethod = createMethod.MakeGenericMethod(runtimeType);
        genericCreateMethod.Invoke(null, new[]{obj});
    }

    private static void CreateGeneric<T>(T obj)
    {
        var generic = new Generic<T>();
    }
}

请注意,我假设您需要T obj方法中的CreateGeneric参数。如果您实际上不需要它,则可以更新方法签名并调用反射代码以省略它。