【问题标题】:Can I declare a variable of Type<T> without specifying T at compile time?我可以在编译时声明一个 Type<T> 变量而不指定 T 吗?
【发布时间】:2010-01-14 21:51:33
【问题描述】:

如何动态加载“MyContent”类? 我有 1 个interface&lt;T&gt;、1 个抽象泛型 class&lt;T&gt; 和 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&lt;obj&gt; 更改为 IMyContentInterface&lt;MyObject&gt;,则可以:

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

问题是,在定义IMyContentInterface&lt;T&gt; 时,我不知道第二行中的对象是什么。请问,有人知道如何在 .NET Framework 4.0 中做到这一点吗?

【问题讨论】:

标签: c# .net generics assemblies


【解决方案1】:

&lt; &gt; 中的项目必须是类型而不是对象。

我的车是 car 类型的对象,所以

Car myCar=new Car();

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

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

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

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

【讨论】:

    【解决方案2】:

    如何动态加载“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() 并且这与泛型类型参数 &lt;T&gt; 没有任何关系,请考虑声明一个非泛型接口,您可以在继承层次结构中的某处实现并声明您的实例变量使用:

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

    【讨论】:

      【解决方案3】:

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

      也就是说,这里有一个示例,说明您可以如何将它用于您的测试用例。显然你可以改变它。另外,不要错过我在此答案末尾的最后说明。

      组装 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 中提取的一个术语。此程序集引用MyCompany.MyProduct.MyComponent,但不引用MyCompany.MyProduct.MyComponent.Implementation,假设接口比产品开发期间的实现更有可能保留compatible。这种设计是为了支持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 是为解决您正在处理的问题而构建的。使用它一段时间后,我自信地说它具有以下优点:

      • 学习曲线相对较短。
      • 因此代码非常简洁。
      • 运行时成本低(程序集小,性能相当好)。

      如果它满足以下一项或多项的任意组合,我会很容易地向从事新应用程序的人推荐它作为严肃可行的选择:

      • 应用程序分为多个组件(几乎所有重要的应用程序都会如此)。
      • 应用程序需要在未来具有灵活性或可扩展性(就像任何长期项目一样)。
      • 应用程序需要从未知程序集中动态加载实现。

      【讨论】:

        【解决方案4】:

        这是一种动态加载接口的方法。这假设您有某种方法可以获取您尝试从中加载它的程序集以及类型名称的字符串。

        在我的例子中,我使用了一个 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;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-10-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多