Reputation: 63
I have the following code:
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>
}
}
Is it possible to instantiate a generic class from a derived method with the current type instead of the base type?
Upvotes: 3
Views: 80
Reputation: 23218
The problem is it's resolving T
to the compile time type of where you're calling the method. In this case, it's being called/resolved from within Foo.Something
and the compile-time type of this
is Foo
, not Bar
.
One option is to make the call virtual
and have each type override
it. This will make each time provide compile-time type information when calling the method:
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);
}
}
Another option is to use the Dynamic Language Runtime to have it resolve the type at runtime:
public class Foo
{
public void DoSomething()
{
dynamic thisDynamic = this;
DoSomething(thisDynamic);
}
private static void DoSomething<T>(T obj)
{
var generic = new Generic<T>();
}
}
EDIT: If you're not using .NET 4.0 and don't have access to the Dynamic Language Runtime, you can employ generics as well:
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>();
}
}
Note that I'm assuming you need the T obj
parameter in the CreateGeneric
method. If you don't actually need it, you can update the method signature and calling reflection code to omit it.
Upvotes: 3
Reputation: 1502096
The compile-time type of this
within Foo.DoSomething
is just Foo
, so the compiler can only infer the type argument as Foo
.
The simplest way of getting it to do it based on the execution-time type is probably:
DoSomething((dynamic) this);
Alternatively, you could call it with reflection yourself.
Upvotes: 5