简体   繁体   中英

Can I dynamically specify the type when creating an instance of a generic interface?

I have got a bit stuck with working out how to pass a data object to its processor class. I have attempted to give a simplified example of the problem below. I'm trying to figure out if there is a type safe way to instantiate the processor using the generic interface?

Cheers,

Charlie

class APieceOfState
    {
        public string AbitOfData { get; set; }
    }

interface IDescribeSomething<in T> 
    {
        void Process(T type) ;
    }


 class ImplementWhatIsDescribed : IDescribeSomething<APieceOfState>
    {
        public void Process(APieceOfState type)
        {
            Console.WriteLine("Processing {0}", type.GetType());
        }

    }

 private static void Main(string[] args)
    {
        var nextTest = new ImplementWhatIsDescribed();
        var newStateObj = new APieceOfState();
        nextTest.Process(newStateObj);

        // Map processor to data in a dictionary
        var dic = new Dictionary<Type, Type>();
        var task = new APieceOfState();
        var taskProcessor = new ImplementWhatIsDescribed();
        dic.Add(task.GetType(), taskProcessor.GetType());

        // Lookup processor using data type
        Type lookupProcessorType;
        dic.TryGetValue(task.GetType(), out lookupProcessorType);

        //                                   vvvvvvvvvvv - How can I make this dynamic based on task.GetType()  ?
        var instance = (IDescribeSomething<APieceOfState>)Activator.CreateInstance(lookupProcessorType);
        instance.Process(task);

        Console.ReadKey();
    }

First option - you can just use dynamic (not strongly typed)

dynamic instance = Activator.CreateInstance(lookupProcessorType);
instance.Process(task);

If you need compile time checks you'll have to go non-generic interface OR generic method that uses generic interface. The reason is IFoo<OneType> and IFoo<OtherType> are not related by inheritance so there is no common static type you can refer to both.

Sample for non-generic interface:

interface IDescribeSomething
{
   void Process(SomeBaseType type);
}


IDescribeSomething instance = 
    (IDescribeSomething)Activator.CreateInstance(lookupProcessorType);
instance.Process(task);

Sample for generic + base similar to IEnumrable<T> . Note that it generally does not solve your problem but at least some other places can have generic code:

interface IDescribeSomething
{
   void Process(SomeBaseType type);
}

interface IDescribeSomething<T> : IDescribeSomething
{
   void Process(T type);
}

class APieceOfState : SomeBaseType {}

class ImplementWhatIsDescribed : IDescribeSomething<APieceOfState>
{
    public void Process(SomeBaseType type)
    {
        Process((APieceOfState)type);
    }
    public void Process(APieceOfState type)
    {
        Console.WriteLine("Processing {0}", type.GetType());
    }

}

IDescribeSomething instance = 
     (IDescribeSomething)Activator.CreateInstance(lookupProcessorType);
instance.Process(task);

// but in this case you can sometime write strongly type one too
// if you got strongly typed version of interface 
IDescribeSomething<APieceOfState> p =...
p.Process(task)

Sample of strongly typed generic method

void DoProcess<T>(T task)
{
   IDescribeSomething<T> instance = 
     (IDescribeSomething<T>)Activator.CreateInstance(lookupProcessorType);
   instance.Process(task);

}

You can invoke this method by using MakeGenricMethod - How do I use reflection to call a generic method?

Do you want something like this ?

public void Process<T>(T type) where T : ICommon
{
    Console.WriteLine("Processing {0}", type.GetType());
}

public interface ICommon
{

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM