Activator.CreateInstance:类的动态实例化

发布于 2024-09-24 04:39:46 字数 2134 浏览 2 评论 0 原文

我正在设计一个松耦合的结构。我想通过由字符串表示的代码从不同的程序集/命名空间调用类。我的设计是,每个客户端的业务规则都位于不同的程序集上,并且彼此不依赖(一个客户端与一个 DLL 的比例),这样当我对 1 个客户端的业务规则进行更新时,不会影响其他客户端。我现在的注意力是使用 Factory Design 和使用 Activator.CreateInstance() 方法。

这是项目设置(2+n DLL)

 namespace Foundation; // where the interfaces/abstract resides
 namespace Factory; // has dependency on Foundation assembly
 namespace Client1; // client1's DLL, no dependency
 namespace Client2; // client2's DLL, no dependency
 The UI // only referenced to the Foundation and Factory not the Clients

实际代码

 namespace Foundation
 {
   public interface IBusinessRules
   {
     string GetBusinessRule();
  }
 }

 namespace Client1 //DLL for client 1
 {
   public class BusinessRules : Foundation.IBusinessRules
   {
    public string GetBusinessRule()
    {
        return "Client1 Business Rule";
    }
   }
}

namespace Client2 //DLL for client 2
{
   public class BusinessRules : Foundation.IBusinessRules
   {
     public string GetBusinessRule()
     {
        return "Client2 Business Rule";
     }
   }
}


namespace Factory
{
  public static class Invoker<T> where T: Foundation.IBusinessRules
  {
    public static T FetchInstance(string clientCode) 
    {
        return (T)Activator.CreateInstance(Type.GetType(clientCode));   
    }
  }
}


 //sample implementation that generates unhandled Exception
 using Factory;
 using Foundation;
 static void Main(string[] args)
 {
      //the parameter is maintained in the database
       IBusinessRules objClient1 = Invoker<IBusinessRules>.FetchInstance("Client1"); 

       //should call Client1.BusinessRules method
        Console.WriteLine(objClient.GetBusinessRule());  
        Console.Read();

        objClient = Invoker<IBusinessRules>.FetchInstance("Client2");

        //should call Client2.BusinessRules method
        Console.WriteLine(objClient.GetBusinessRule()); 
        Console.Read();      
  }

知道为什么我的示例不起作用吗?有什么改进设计的建议吗? 提前致谢。

如何使用

表达式.Lambda

有人吗?

I am designing a loosely-coupled structure. I want to call classes from different assemblies/namespaces via a code which is represented by a String. My design is, each of client's business rules is on different assemblies and not dependent on each other (ONE client is to ONE DLL ratio) so that when I made an update on business rules of 1 client, it would not affect the others. My attention now is on using Factory Design and using Activator.CreateInstance() Method.

This is the project setup (2+n DLL's)

 namespace Foundation; // where the interfaces/abstract resides
 namespace Factory; // has dependency on Foundation assembly
 namespace Client1; // client1's DLL, no dependency
 namespace Client2; // client2's DLL, no dependency
 The UI // only referenced to the Foundation and Factory not the Clients

The actual code

 namespace Foundation
 {
   public interface IBusinessRules
   {
     string GetBusinessRule();
  }
 }

 namespace Client1 //DLL for client 1
 {
   public class BusinessRules : Foundation.IBusinessRules
   {
    public string GetBusinessRule()
    {
        return "Client1 Business Rule";
    }
   }
}

namespace Client2 //DLL for client 2
{
   public class BusinessRules : Foundation.IBusinessRules
   {
     public string GetBusinessRule()
     {
        return "Client2 Business Rule";
     }
   }
}


namespace Factory
{
  public static class Invoker<T> where T: Foundation.IBusinessRules
  {
    public static T FetchInstance(string clientCode) 
    {
        return (T)Activator.CreateInstance(Type.GetType(clientCode));   
    }
  }
}


 //sample implementation that generates unhandled Exception
 using Factory;
 using Foundation;
 static void Main(string[] args)
 {
      //the parameter is maintained in the database
       IBusinessRules objClient1 = Invoker<IBusinessRules>.FetchInstance("Client1"); 

       //should call Client1.BusinessRules method
        Console.WriteLine(objClient.GetBusinessRule());  
        Console.Read();

        objClient = Invoker<IBusinessRules>.FetchInstance("Client2");

        //should call Client2.BusinessRules method
        Console.WriteLine(objClient.GetBusinessRule()); 
        Console.Read();      
  }

Any idea why my sample doesn't work? And any suggestion to improve the design?
Thanks in advance.

How about using

Expression.Lambda

anyone?

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

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

发布评论

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

评论(5

清旖 2024-10-01 04:39:46

如果您使用 FetchInstance("Client.BusinessRules") 您的代码可以工作,前提是所有内容都在同一个程序集中。如果不是(根据您的设计),您需要提供 AssemblyQualifiedName

不过我会做不同的设计。保留仅使用“Client1”作为参数的调用,但更改工厂的实现。动态加载给定客户端的程序集(使用 Assembly.Load() 或 Assembly.LoadFrom()),然后使用 clientAssembly.CreateInstance() 实例化您的类型。

编辑:原始代码示例:

namespace Factory
{
  public static class Invoker<T> where T: IBusinessRules
  {
    public static T FetchInstance(string clientCode)
    {
        var clientAssembly = Assembly.LoadFrom(clientCode + ".dll");

        return (T)clientAssembly.CreateInstance(clientCode+".BusinessRules");
    }
  }
}

如果您不知道 client-dll 中的类名,则必须搜索适用的类型,例如使用 clientAssembly.GetTypes()。

If you use FetchInstance("Client.BusinessRules") your code works, IF everything is in the same assembly. If it's not (as per your design) you need to give an AssemblyQualifiedName.

I would do the design differently though. Keep your call with just "Client1" as Parameter but change the implementation of the Factory. Dynamically load the assembly for the given client (with Assembly.Load() or Assembly.LoadFrom()), then use clientAssembly.CreateInstance() to istantiate your type.

Edit: Crude code sample:

namespace Factory
{
  public static class Invoker<T> where T: IBusinessRules
  {
    public static T FetchInstance(string clientCode)
    {
        var clientAssembly = Assembly.LoadFrom(clientCode + ".dll");

        return (T)clientAssembly.CreateInstance(clientCode+".BusinessRules");
    }
  }
}

If you dont't know the class name in the client-dll, you have to search for an applicable Type, for example with clientAssembly.GetTypes().

孤独患者 2024-10-01 04:39:46

感谢你们的帮助,我终于明白了!我只是修改了工厂

 namespace Factory
 {
    public static class Invoker<T> where T : Foundation.IBusinessRules
    {
        public static T FetchInstance(string clientCode)
        {
           Type objType = Type.GetType(clientCode + ".BusinessRules," + clientCode);
           return (T)Activator.CreateInstance(objType);

    }
}

,但我想知道它的效率(性能影响),因为它使用反射..

Thanks to your help guys i finally Got it! I just modify the Factory

 namespace Factory
 {
    public static class Invoker<T> where T : Foundation.IBusinessRules
    {
        public static T FetchInstance(string clientCode)
        {
           Type objType = Type.GetType(clientCode + ".BusinessRules," + clientCode);
           return (T)Activator.CreateInstance(objType);

    }
}

But I wonder about its effeciency (performance hit) because it uses Reflection..

眼泪都笑了 2024-10-01 04:39:46

您需要使用班级的全名。

例如:

Type.GetType("System.Collections.Generic.Dictionary`2[System.String,[MyType,MyAssembly]]")

You need to use the full name of the class.

for example:

Type.GetType("System.Collections.Generic.Dictionary`2[System.String,[MyType,MyAssembly]]")
忆沫 2024-10-01 04:39:46

如果您从外部程序集加载类型,我建议使用Activator.CreateInstanceFrom

var typeReference = Activator.CreateInstanceFrom(assemblyPath, fullyQualifiedClassName);
return typeReference.Unwrap() as T;

If you are loading the type from an external assembly, I would recommend using Activator.CreateInstanceFrom.

var typeReference = Activator.CreateInstanceFrom(assemblyPath, fullyQualifiedClassName);
return typeReference.Unwrap() as T;
江挽川 2024-10-01 04:39:46

如果您希望能够在部署后将业务规则添加为 dll 并在运行时创建它们,我建议您在应用程序下有一个业务规则文件夹,加载该应用程序中的所有 dll,搜索每个 dll 中实现 IBusinessRules 的所有类型使用反射。鉴于您现在已经掌握了这些类型,因此根据名称创建一个类型将很容易,并且您的项目将会扩展。

或者,或者将类的程序集限定名称传递给您的方法。

If you want to be able to add business rules as dlls after deployment and create them at runtime, I suggest you have a business rules folder under you app, load all dlls in that app, search for all types that implement of IBusinessRules in each dll using reflection. Given that you now have handles on the types, creating one based on name would be easy and your project would scale out.

Either that, or pass the assembly qualified name of the classes to your methods.

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