locked
C++/CX - Is it possible to use Interfaces in templates

    Question

  • I'm working on an IOC container for C++/CX and am unable access an interface via a template.   For example I would like to be able to do the following:

    container->Register(TypeOf<ITest>(), ref new TestWoof()); 

    However I have to use the following convention because I can't get the type of T if it is an interface:

    I blog on the topic on the following link:

    http://global-webnet.com/blog/post/2013/03/05/CppCx-IOC-Dependency-Injection.aspx

    Note above that I have to use ResolveProxy to get the actual implementation:

    template <typename T>
    static T^ ResolveProxy(IContainer^ container) 
    {	
    	// Returns implementation of proxy from container
    	auto proxyImplementation = container->Resolve(TypeOf<T>());
    
    	// If the implementation implements IHasContainer then the 
    	// implementation's Container will be set with parameter container
    	auto containerObj = dynamic_cast<IHasContainer^>(proxyImplementation);
    	if(containerObj!=nullptr)
    		containerObj->Container = container;
    
    	// We can't return the implementation because it is not of type T,
    	// T is a proxy class which is expected to be returned.  As such 
    	// we have to instantiate a new proxy (type T) to return and set it 
    	// with the proxy implementation stored in the container.
    	auto proxy = ref new T();
    
    	// If T does not implement IInterfaceProxy you will get a SetInstance compile
    	// error here.
    	proxy->SetInstance(proxyImplementation);
    
    	// Return the proxy class which now contains an instance of the
    	// Implementation that was registered in the container
    	return proxy;
    }
    

    The implementation of IInterfaceProxy looks as follows:

    namespace GwnLibraryTest {
    	namespace Mocks {
    
    		public interface class ITest : public IHasContainer
    		{
    			String^ Speak();
    		};
    
    		public ref class ITestProxy sealed : public IInterfaceProxy
    		{
    		public:
    
    			static property Object^ Instance;
    
    			// Let developer know if invalid cast
    			// (wrong type used in SetInstance)
    			ITest^ GetITestInstance()
    			{	
    				return static_cast<ITest^>(Instance);
    			}
    
    			virtual void SetInstance(Object^ instance)
    			{
    				Instance = instance;
    			}
    		};
    
    	}
    }

    While the implementation of ITest (the actual interface we are using the proxy for) follows:

    namespace GwnLibraryTest {
    	namespace Mocks {
    
    		public ref class TestMeow sealed : public ITest
    		{
    		private:
    			ClassBase^ _base;
    
    		public:
    			TestMeow(){ _base = ref new ClassBase(); }
    
    			virtual property IContainer^ Container {
    				void set(IContainer^ value) { _base->Container = value ;}
    				IContainer^ get() { return _base->Container; }
    			};
    
    			virtual String^ Speak(){
    				String^ meow = "Meow";
    				_base->Logger->Log("Cats go {0} when they talk",meow);
    				return meow;
    			};
    	
    		};
    	}
    }

    MCAD.NET C# - http://www.Global-webnet.com/Blog


    • Edited by BillKrat1 Sunday, March 10, 2013 12:52 PM New code better reflects issue and work-around
    Wednesday, March 6, 2013 3:40 AM

Answers

All replies

  • Wow, It's a great job.

    NEU_ShieldEdge

    Thursday, March 7, 2013 3:13 AM
  • Thank you!  I've uploaded the source to http://PasswordMgr.CodePlex.com - I will continue development there.

    MCAD.NET C# - http://www.Global-webnet.com/Blog

    • Marked as answer by Jesse Jiang Monday, March 11, 2013 2:27 AM
    Sunday, March 10, 2013 2:16 PM
  • Frantise Kaduk provided me an alternate solution which I refactored into my http://PasswordMgr.CodePlex.com project - it permits me to do the following:

    TEST_METHOD(CanResolveInterface)  
    {   
        auto bootstrapper = ref new MockBootstrapper();   
        auto container = bootstrapper->Container;

        // Register implementation for ITest (TestWoof)  
        Register<ITest, TestWoof>(container);

        auto woof = Resolve<ITest>(container);     
        Assert::IsNotNull(woof, "Expected instance of woof");   
    }

    Blogged about on the following link:

    http://global-webnet.com/blog/post/2013/04/07/template-specialization-in-CppCX.aspx


    MCAD.NET C# - http://www.Global-webnet.com/Blog

    Sunday, April 7, 2013 12:35 PM