Domanda

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?

È stato utile?

Soluzione

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.

Altri suggerimenti

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top