我可以在编译时声明Type <t>的变​​量而不指定T吗?</t>

时间:2010-01-14 21:51:34

标签: c# .net generics assemblies

如何动态加载“MyContent”类? 我有1个interface<T>,1个抽象通用class<T>和1个类。检查我的代码:

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 }
}

我正在尝试,但显然它不起作用:

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

如果我将IMyContentInterface<obj>更改为IMyContentInterface<MyObject>,则可以:

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

问题在于,在定义IMyContentInterface<T>时,我不会在第二行中成为我的对象。请问,有人知道如何在.NET Framework 4.0中执行此操作吗?

4 个答案:

答案 0 :(得分:7)

< >中的项目必须是类型而非对象。

我的车是汽车类型的物体,所以

Car myCar=new Car();

我想要一个列表来保存我的汽车(Car类型的物品)。

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

然后我们将Car类型的对象添加到我的列表中。

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

答案 1 :(得分:5)

  

如何动态加载“MyContent”类?

正在加载并不难 - 您已经知道如何做到这一点,但C#泛型在编译时是强类型,检查和保证。请考虑以下代码:

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

如果允许你声明这样的泛型,C#编译器无法告诉你这是非法的:

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

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

如果您的最终目标是调用MyContent.MyMethod()且与泛型类型参数<T>无关,请考虑声明可以在继承层次结构中的某个位置实现的非泛型接口并使用它声明您的实例变量:

IMyContentInterface content = (IMyContentInterface)Assembly.Load("MyAssembly").CreateInstance("MyContent");
content.MyMethod();

答案 2 :(得分:5)

我不得不读了几遍,但我想出了你在问什么。 :)这个问题是另一个问题的具体实例:

那就是说,这是一个如何将它用于测试用例的示例。显然你可以改变它。另外,请不要错过本回答末尾的最后一点。

Assembly MyCompany.MyProduct.MyComponent:

在此程序集中定义接口:

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
    {
    }
}

汇编MyCompany.MyProduct.MyComponent.Implementation:

在此程序集中实现将动态加载的接口。

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() { }
    }
}

汇编MyCompany.MyProduct

你的程序是撰写在这个程序集中,这是我从Managed Extensibility Framework中提取的一个术语。在假设接口比产品开发期间的实现更可能保持compatible的情况下,此程序集引用MyCompany.MyProduct.MyComponent但不引用MyCompany.MyProduct.MyComponent.Implementation。这种设计试图偏向cohesion over coupling(一对经常被误解的词),但实际的实现往往在实现这一目标的过程中发生了很大的变化。

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);
        }
    }
}

最后注释:

Managed Extensibility Framework是作为您正在处理的问题的常见解决方案而构建的。经过一段时间的努力,我充满信心地说它具有以下不错的特性:

  • 相对较短的学习曲线。
  • 非常干净的代码。
  • 运行成本低(组装很小,性能非常好)。

如果符合以下一项或多项任务的任何组合,我会很容易地将其推荐为从事新应用程序工作的人员:

  • 应用程序分为几个部分(几乎任何非平凡的应用程序都是如此)。
  • 将来应用程序需要灵活或可扩展(因为任何长期项目都是如此)。
  • 应用程序需要从未知程序集动态加载实现。

答案 3 :(得分:1)

这是一种动态加载接口的方法。这假设你有一些方法来获取你试图加载它的程序集和一个字符串作为类型的名称。

在我的情况下,我使用了一个Xml文件。您可以使用任何方法,我不会显示这些方法,因为它可以根据您的实现进行更改。

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;
}