Sri Reddy
Sri Reddy

Reputation: 7012

C# - Cast generic interface to generic class that pass type <T> that is determined at runtime

How can I cast a generic class with generic interface by passing Type that is determined at runtime?

public class SomeDataChanged
    {
        public string EventName { get; set; }
    }

public class MessageSub<T> where T : class
{
    public IMessageBus Bus { get; set; }
    public ISubscription<T> Sub { get; set; }
}

public interface IDataChangedService<T> where T : class
{
    MessageSub<T> ProcessData(string topic, string subscription);
}

public class DataChangedService<T> : IDisposable, IDataChangedService<T> where T : class
{
    public MessageSub<T> ProcessData(string topic, string subscription)
    {
        // Some code
    }

    // More code
}

I have used reflection to pass type determined at runtime to the generic class using the following thread. But not getting how to cast it to another generic type.

class Test
{
    static void Main()
    {
        string topic = "OrderChanged";
        string subscription = "MyUi";
        string typeName = "OrderDataChanged";
        Type T = Type.GetType(typeName);

        Type genericClass = typeof(DataChangedService<>);
        Type constructedClass = genericClass.MakeGenericType(T);

        //How to cast another generic interface to my constructed class?
        var obj = (IDataChangedService<T>)Activator.CreateInstance(constructedClass); 

        //Also how to return generic type object?
        MessageSub<T> msgSub = obj.ProcessData(topic, subscription);

        // and, then some code that use msgSub
    }
}

Upvotes: 1

Views: 834

Answers (1)

Enigmativity
Enigmativity

Reputation: 117175

You can't do IDataChangedService<T>. The T is a run-time variable of type System.Type, and not a compile-time type represented by the string typeName. To use generic parameters the type must be compile-time.

You need to introduce some non-generic types to make this work.

Something like this:

public interface IMessageSub { }

public class MessageSub<T> : IMessageSub where T : class
{
    public IMessageBus Bus { get; set; }
    public ISubscription<T> Sub { get; set; }
}

public interface IDataChangedService
{
    IMessageSub ProcessData(string topic, string subscription);
}

public interface IDataChangedService<T> : IDataChangedService where T : class
{
    MessageSub<T> ProcessData(string topic, string subscription);
}

public class DataChangedService<T> : IDataChangedService<T> where T : class
{
    IMessageSub IDataChangedService.ProcessData(string topic, string subscription)
    {
        return this.ProcessData(topic, subscription);
    }

    public MessageSub<T> ProcessData(string topic, string subscription)
    {
        // Some code
    }

    // More code
}

Then you can do:

var obj = (IDataChangedService)Activator.CreateInstance(constructedClass);

obj.ProcessData(topic, subscription);

Upvotes: 3

Related Questions