views:

389

answers:

5

How do I Load the class "MyContent" dynamically ? I have 1 interface<T>, 1 abstract generic class<T> and 1 class. Check my code out:

public interface IMyObjectInterface{
}
public abstract MyAbstractObject : IMyObjectInterface{
}
public class MyObject : MyAbstractObject{
}

public interface IMyContentInterface<T>  where T : MyAbstractObject
{
  void MyMethod();
}
public abstract MyAbstractContent<T>, IMyContentInterface<T>  where T : MyAbstractObject
{
  public abstract void MyMethod();
}
public public class MyContent : MyAbstractContent<MyObject>
{
  public override void MyMethod() { //do something }
}

I am trying but obviously it's not working:

IMyObjectInterface obj = (IMyObjectInterface)Assembly.Load("MyAssembly").CreateInstance("MyObject");
IMyContentInterface<obj> content = (IMyContentInterface<obj>)Assembly.Load("MyAssembly").CreateInstance("MyContent");
content.MyMethod();
//assembly and type names are correct

If I change IMyContentInterface<obj> to IMyContentInterface<MyObject>, works :

IMyContentInterface<MyObject> content = (IMyContentInterface<MyObject>)Assembly.Load("MyAssembly").CreateInstance("MyContent");
content.MyMethod();
//assembly and type names are correct

The problem is that i don't what is going to be my object in the 2nd line, when defining IMyContentInterface<T>. Please, does somebody know how to do it in .NET Framework 4.0?

+7  A: 

the item in the < > has to be a type not an object.

my car in an object of the type car so

Car myCar=new Car();

i want a list to keep my cars (objects of type Car) in.

List<Car> myCars = new List<Car>();

And then we add object of type Car to my List.

 myCars.Add(myCar);
 myCars.Add(anotherCar);

Are you fully aware of Object Orientated Programming, it looks like you're jumping in at the deep end a little bit.

runrunraygun
+5  A: 

How do I Load the class "MyContent" dynamically?

Loading it isn't hard - you already know how to do that, but C# generics are strongly-typed, checked and guaranteed at compile time. Consider this code:

List<string> list = new List<string>(); 
list.Add(new TcpSocket()); // This line won't compile

The C# compiler couldn't tell you this was illegal if you were allowed to declare generics like this:

Type type = GetTypeFromReflectedAssembly();
List<type> list = new List<type>();

// This *might* work - who knows?
list.Add(new TcpSocket());

If your ultimate goal is to call MyContent.MyMethod() and that doesn't have anything to do with the generic type parameter <T>, consider declaring a non-generic interface you can implement somewhere in your inheritance hierarchy and declare your instance variable using that:

IMyContentInterface content = (IMyContentInterface)Assembly.Load("MyAssembly").CreateInstance("MyContent");
content.MyMethod();
Jeff Sternal
+1  A: 

This is a way to dynamically load a Interface. This assumes you have some way of getting the assembly you are trying to load it from and a string for the name of the type.

In my case I used an Xml file. You can use any, I don't show those methods, because it can change per your implementation.

ISomeInterface myInterface = this.GetComponent<ISomeInterface>("SomeImplementation");


public T GetComponent<T>(string componentName)
{
    // A method to dymanicly load a .dll, not shown in this example
    Assembly assembly = this.GetComponentAssembly(componentName);

    // A method to get a string assembly type, in this case from another source
    string assemblyType = this.GetAssemblyType(componentName);

    T component = (T)assembly.CreateInstance(assemblyType);

    return component;
}
David Basarab
+4  A: 

I had to read this a few times, but I figured out what you're asking. :) This question is a specific instance of this other question:

That said, here's an example of how you might use it for your test case. Obviously you can vary it. Also, don't miss my final note at the end of this answer.

Assembly MyCompany.MyProduct.MyComponent:

Define your interfaces in this assembly:

namespace MyCompany.MyProduct.MyComponent
{
    public interface IMyObjectInterface
    {
        void MyObjectMethod();
    }

    /* It's important to include this non-generic interface as a base for
     * IMyContentInterface<T> because you will be able to reference this
     * in the assembly where you load components dynamically.
     */
    public interface IMyContentInterface
    {
        Type ObjectType
        {
            get;
        }

        void MyContentMethod();
    }

    public interface IMyContentInterface<T> : IMyContentInterface
        where T : IMyObjectInterface
    {
    }
}

Assembly MyCompany.MyProduct.MyComponent.Implementation:

Implement the interfaces in this assembly that will be dynamically loaded.

namespace MyCompany.MyProduct.MyComponent
{
    public abstract class MyAbstractObject : IMyObjectInterface
    {
        public abstract void MyObjectMethod();
    }

    public class MyObject : MyAbstractObject
    {
        public override void MyObjectMethod() { }
    }

    public abstract class MyAbstractContent<T> : IMyContentInterface<T>
        where T : MyAbstractObject
    {
        public Type ObjectType
        {
            get
            {
                return typeof(T);
            }
        }

        public abstract void MyContentMethod();
    }

    public class MyContent : MyAbstractContent<MyObject>
    {
        public override void MyContentMethod() { }
    }
}

Assembly MyCompany.MyProduct

Your program is composed in this assembly, a term I pulled from the Managed Extensibility Framework. This assembly references MyCompany.MyProduct.MyComponent but not MyCompany.MyProduct.MyComponent.Implementation under the assumption that the interfaces are more likely to remain compatible than the implementations during product development. This design is an attempt to favor cohesion over coupling (a pair of often misunderstood words), but the actual implementations tend to vary heavily in their success of achieving this goal.

namespace MyCompany.MyProduct
{
    using MyCompany.MyProduct.MyComponent;
    using System.Reflection;
    using System.Security.Policy;

    public class ComponentHost
    {
        public void LoadComponents()
        {
            Assembly implementation = LoadImplementationAssembly();

            /* The implementation assembly path might be loaded from an XML or
             * similar configuration file
             */
            Type objectType = implementation.GetType("MyCompany.MyProduct.MyComponent.MyObject");
            Type contentType = implementation.GetType("MyCompany.MyProduct.MyComponent.MyContent");

            /* THIS assembly only works with IMyContentInterface (not generic),
             * but inside the implementation assembly, you can use the generic
             * type since you can reference generic type parameter in the source.
             */
            IMyContentInterface content = (IMyContentInterface)Activator.CreateInstance(contentType);
        }

        private Assembly LoadImplementationAssembly()
        {
            /* The implementation assembly path might be loaded from an XML or
             * similar configuration file
             */
            string assemblyPath = "MyCompany.MyProduct.MyComponent.Implementation.dll";
            return Assembly.LoadFile(assemblyPath);
        }
    }
}

Final Note:

The Managed Extensibility Framework was built as a common solution to the problem you are working on. Having worked with it for a while now, I say with confidence that it has the following nice properties:

  • Relatively short learning curve.
  • Very clean code as a result.
  • Low runtime cost (the assembly is small and performance is quite good).

I would easily recommend it as serious viable option for someone working on a new application if it meets any combination of one or more of the following:

  • The application is divided into components (as almost any non-trivial application would be).
  • The application needs to be flexible or extensible in the future (as any long-term project would be).
  • The application needs to dynamically load an implementation from an unknown assembly.
280Z28
A: 

runrunraygun, I know that the item in the < > has to be a type not an object. That's why i said "obviously it's not working". Even if I put the type of my object which is IMyObjectInterface or MyAbstractObject, it won't work. At run time, you get an error Unable to Cast.

280Z28 and Jeff answered the problem. Thank you! Unfortunatly MyContent.MyMethod() has to do with <T>, and my mistake forgetting to add in the problem.

I have methods that use <T>. What to do then?

Here's the code again:

public interface IMyObjectInterface{
}
public abstract MyAbstractObject : IMyObjectInterface{
}
public class MyObject : MyAbstractObject{
}

public interface IMyContentInterface<T>  where T : MyAbstractObject
{
  T MyMethod();
  void MyMethod2(T);
}
public abstract MyAbstractContent<T>, IMyContentInterface<T>  where T : MyAbstractObject
{
  public abstract T MyMethod();
  public abstract void MyMethod2(T);
}
public class MyContent : MyAbstractContent<MyObject>
{
  public override MyObject MyMethod() { //do something with MyObject }
  public override void MyMethod2(MyObject) { //do something with MyObject }
}

That Managed Extensibility Framework is really interesting, I will check that out.

Fabio
@Fabio - given the scenario in your original question, you'll have to declare the variable as an `object` (or as a more suitable non-generic interface that you know at compile time) and call the methods you're interested in using reflection.
Jeff Sternal