locked
It is possible to call a method on a generic type parameter RRS feed

  • Question

  • I'm new in C# and I try to use generics to simplify my code, I'm in the following situation: I have to use some COM classes that implements different interfaces but the methods expose by the different interfaces have the same signature, so in order to avoid generate a set of wrapper classes for each COM component i try to use c# generics.

    More in detail I define a new Interface and a concrete generic class that implements it, the generic type parameters are: the COM interface and the COM coclass. That should allow me to write something like that (using different COM object as a providers)

     

    IRunTime RT = new RunTime<MyCOMInterface,MyCOMCoClass>;
    RT.StoreObject();
     
        interface IRunTime
        {
            int StoreObject();
        }

        public class RunTime<I, T> : IRunTime
            where T : class, new()
            where I : class
        {
            public RunTime()
            {
                _Interface = new T() as I;
            }

            public void DestroyInstance()
            {
                _Interface = null;
            }

            public I Interface
            {
                get
                {
                    return _Interface;//as I;
                }
            }

            public virtual int StoreObject()
            {
                return _Interface.StoreData();
            }

            private I _Interface;
        }

    But the compiler seems does not allow this because it does not know the generic type parameter ('I' does not contain a definition for 'StoreData' and no extension method 'StoreData' accepting a first argument of type 'I' could be found (are you missing a using directive or an assembly reference?))

    Is there a way to overcome this limitation? Also a different solution to my problem is welcome.

    Thanks

     

    Thursday, January 26, 2012 8:04 PM

Answers

  • Hi Simone,

    That is because the type I in your generic class definition only knows the protogenetic members of a "class" type, as it inherits "class" type with the statement of "where I : class". As we all know the protogenetic "class" type does not have a StoreData method. This method is only known at runtime after the generic type is reified to, e.g., MyCOMInterface.

    So here we should utilize reflection, which will check the method at runtime. Here we only need to make a small modification on the definition of the StoreObject method as below:
            public virtual int StoreObject()
            {
                object result = _Interface.GetType().GetMethod("StoreData").Invoke(_Interface, null);
                return Convert.ToInt32(result);
            }
    

    Please check it out first, here I am waiting for your feedback.

    Have a nice day, 
    Leo Liu [MSFT]
    MSDN Community Support | Feedback to us
    Monday, January 30, 2012 8:59 AM
    Moderator

All replies

  • You have to include some restrictions so the compiler can assure that the StoreData method will always exist.

    The only real way to overcome this is to define a new interface which defines the StoreData() method. Then force all of your COM interfaces to derive from your new method, and add a type restriction so that only instances of your new interface can be used for your class.


    Check out My Blog. Now updated to actually work!
    • Proposed as answer by servy42 Monday, January 30, 2012 4:46 PM
    Thursday, January 26, 2012 8:33 PM
  • I think this does what Tim is suggesting above.

    At the very least it compiles & executes:

    public class RunTime<I, T> : IRunTime
        where I : class, IStoreData
        where T : class, new()
    {
        private I _Interface;
    
        public RunTime()
        {
            _Interface = new T() as I;
        }
    
        public I Interface
        {
            get { return _Interface; }
        }
    
        public virtual int StoreObject()
        {
            return _Interface.StoreData();
        }
    }
    
    public class MyCOMCoClass : MyCOMInterface
    {
        public int StoreData()
        {
            throw new NotImplementedException();
        }
    }
    
    public interface MyCOMInterface : IStoreData
    {
            
    }
    
    public interface IStoreData
    {
        int StoreData();
    }
    
    public interface IRunTime
    {
        int StoreObject();
    }
    

    If I got it wrong could you provide a little more information?

    You can call it in the exact same way as you posted:

    IRunTime rt = new RunTime<MyCOMInterface, MyCOMCoClass>();
    
    rt.StoreObject();
    
    


    Thursday, January 26, 2012 8:47 PM
  • Thank for the answer but I'm not the owner of these COM interfaces and what I post is just an example, the COM interfaces espose more ore less 30 methods and your answer is what I want to avoid: generate a set of C# wrapper classes one for each COM interface that deriva from the same interface
    Thursday, January 26, 2012 8:49 PM
  • Sorry Scotty_ my answer was for Tim.... but I think it is also valid for you I cannot change the COM interfaces that are the real problem of the component they expose the same features using the same methods signature by means of different interfaces instead of using (implement) the same interface
    Thursday, January 26, 2012 8:59 PM
  • Hi Simone78GE,

    If they are out of your control, and they all implement different interfaces, that just happen to have the same method signature, I can't think of any solutions to make it work.

    My first thought was perhaps to use reflection to try and access the method, but I'm not very confident in explaining that process as I have very little experience with it.

    Maybe another member here has a solution for you?

    Thursday, January 26, 2012 9:07 PM
  • Hi Again,

    I was able to get this to work after a quick search on MSDN about reflection. 

    Perhaps try this in a new Console Application so you can see how it's working, and whether it will work for you.  I was able to cut out almost everything related to the interfaces.

    namespace ConsoleApplication2
    {
        internal class Program
        {
            private static void Main(string[] args)
            {
                var rt = new RunTime<MyCOMCoClass>();
    
                int value = rt.StoreObject();
            }
        }
    
        public class RunTime<T>
            where T : class
        {
            public virtual int StoreObject()
            {
                object obj = typeof (T).InvokeMember(null,
                                                     BindingFlags.DeclaredOnly |
                                                     BindingFlags.Public | BindingFlags.NonPublic |
                                                     BindingFlags.Instance | BindingFlags.CreateInstance, 
                                                     null, null, null);
    
                return (int)
                       typeof (T).InvokeMember("StoreData",
                                               BindingFlags.DeclaredOnly |
                                               BindingFlags.Public | BindingFlags.NonPublic |
                                               BindingFlags.Instance | BindingFlags.InvokeMethod,
                                               null, obj, null);
            }
        }
    
        public class MyCOMCoClass
        {
            public int StoreData()
            {
                return 1;
            }
        }
    }
    
    

    I'm not 100% sure what everything is doing, but the reference page I used can be found here:

    http://msdn.microsoft.com/en-us/library/66btctbe.aspx

     

    Thursday, January 26, 2012 9:37 PM
  • Hi Simone,

    That is because the type I in your generic class definition only knows the protogenetic members of a "class" type, as it inherits "class" type with the statement of "where I : class". As we all know the protogenetic "class" type does not have a StoreData method. This method is only known at runtime after the generic type is reified to, e.g., MyCOMInterface.

    So here we should utilize reflection, which will check the method at runtime. Here we only need to make a small modification on the definition of the StoreObject method as below:
            public virtual int StoreObject()
            {
                object result = _Interface.GetType().GetMethod("StoreData").Invoke(_Interface, null);
                return Convert.ToInt32(result);
            }
    

    Please check it out first, here I am waiting for your feedback.

    Have a nice day, 
    Leo Liu [MSFT]
    MSDN Community Support | Feedback to us
    Monday, January 30, 2012 8:59 AM
    Moderator
  • If you don't want to use reflection (I would encourage you not to here, as it's more of a 'hack' then a good solution) then you could look into delegates.  Have your generic class take a delegate which it can later execute, and have all of the classes utilizing it just pass a reference to their StoreData method.
    Monday, January 30, 2012 4:49 PM
  • Hi Simone,

    How is it going now with our friends' suggestion?
    We are looking forward to hearing from you.

    Have a nice day, 

    Leo Liu [MSFT]
    MSDN Community Support | Feedback to us
    Wednesday, February 1, 2012 10:20 AM
    Moderator