我有以下代码:
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>
}
}
是否可以使用当前类型而不是基类型从派生方法实例化泛型类?
答案 0 :(得分:5)
this
中Foo.DoSomething
的编译时类型只是Foo
,因此编译器只能 将类型参数推断为Foo
根据执行时间类型获取它的最简单方法可能是:
DoSomething((dynamic) this);
或者,您可以自己用反射来调用它。
答案 1 :(得分:3)
问题是它正在将T
解析为您调用方法的编译时类型。在这种情况下,它在Foo.Something
内被调用/解析,编译时类型this
为Foo
,而不是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
参数。如果您实际上不需要它,则可以更新方法签名并调用反射代码以省略它。