2

我正在设计一个松散耦合的结构。我想通过由 String 表示的代码从不同的程序集/命名空间调用类。我的设计是,每个客户端的业务规则都在不同的程序集上,并且彼此不依赖(一个客户端与一个 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

任何人?

4

5 回答 5

3

如果您使用 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()。

于 2010-09-16T14:29:56.587 回答
2

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

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

    }
}

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

于 2010-09-16T16:29:23.627 回答
1

您需要使用类的全名。

例如:

Type.GetType("System.Collections.Generic.Dictionary`2[System.String,[MyType,MyAssembly]]")
于 2010-09-16T14:05:46.933 回答
0

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

var typeReference = Activator.CreateInstanceFrom(assemblyPath, fullyQualifiedClassName);
return typeReference.Unwrap() as T;
于 2010-09-16T14:47:57.973 回答
0

如果您希望能够在部署后将业务规则添加为 dll 并在运行时创建它们,我建议您在应用程序下有一个业务规则文件夹,加载该应用程序中的所有 dll,搜索在每个 dll 中实现 IBusinessRules 的所有类型使用反射。鉴于您现在拥有类型的句柄,基于名称创建一个将很容易,并且您的项目将向外扩展。

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

于 2010-09-16T15:23:35.627 回答