我可以声明一个 Type类型的变量吗?编译时不指定T?

发布于 2024-08-17 09:03:58 字数 1431 浏览 2 评论 0原文

如何动态加载“MyContent”类? 我有 1 个 interface、1 个抽象通用 class 和 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 更改为 IMyContentInterface,则有效:

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

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

讽刺将军 2024-08-24 09:03:58

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

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

Car myCar=new Car();

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

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

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

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

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

my car is 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);
此生挚爱伱 2024-08-24 09:03:58

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

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

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();
亢潮 2024-08-24 09:03:58

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

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

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

Assembly 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

您的程序在此程序集中组成,这是我从托管扩展性中提取的术语框架。假定接口更有可能保留 与产品开发期间的实现兼容。这种设计试图支持内聚而非耦合(一对经常被误解的词),但是实际的实施在能否成功实现这一目标方面往往存在很大差异。

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

最后说明:

托管可扩展性框架是作为您正在处理的问题的通用解决方案而构建的。在使用它一段时间后,我自信地说它具有以下良好的特性:

  • 相对较短的学习曲线。
  • 结果代码非常干净。
  • 运行成本低(程序集小,性能相当好)。

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

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

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.
梦巷 2024-08-24 09:03:58

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

就我而言,我使用了 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;
}

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文