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

Fab*_*sta 5 .net c# generics assemblies

如何动态加载"MyContent"类?我有1,1 interface<T>个抽象泛型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 }
}
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

如果我换IMyContentInterface<obj>IMyContentInterface<MyObject>,工作:

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

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

gin*_*boy 7

在该项目< >必须是一个类型不是对象.

我的车是汽车的一个对象所以

Car myCar=new Car();
Run Code Online (Sandbox Code Playgroud)

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

List<Car> myCars = new List<Car>();
Run Code Online (Sandbox Code Playgroud)

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

 myCars.Add(myCar);
 myCars.Add(anotherCar);
Run Code Online (Sandbox Code Playgroud)


Jef*_*nal 5

如何动态加载"MyContent"类?

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

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

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

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

// This *might* work - who knows?
list.Add(new TcpSocket());
Run Code Online (Sandbox Code Playgroud)

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

IMyContentInterface content = (IMyContentInterface)Assembly.Load("MyAssembly").CreateInstance("MyContent");
content.MyMethod();
Run Code Online (Sandbox Code Playgroud)


Sam*_*ell 5

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

也就是说,这是一个如何将它用于测试用例的示例.显然你可以改变它.此外,请不要错过我在答案结尾处的最后一点.

汇编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
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

汇编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() { }
    }
}
Run Code Online (Sandbox Code Playgroud)

汇编MyCompany.MyProduct

您的程序由此程序集组成,这是我从Managed Extensibility Framework中提取的术语.这个程序集引用MyCompany.MyProduct.MyComponent但不是MyCompany.MyProduct.MyComponent.Implementation假设接口比产品开发期间的实现更可能保持兼容.这种设计试图有利于凝聚力而不是耦合(一对经常被误解的词),但实际的实施往往在实现这一目标的过程中有很大差异.

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后注意:

托管扩展框架是建成一个共同的解决方案,您正在使用的问题.经过一段时间的努力,我充满信心地说它具有以下不错的特性:

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

如果它符合以下一项或多项的任何组合,我会很容易地推荐它作为新应用程序工作人员的可行选项:

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