我正在设计一个松散耦合的结构。我想通过一个由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();
}
知道为什么我的样本不起作用?有什么改进设计的建议吗? 提前谢谢。
如何使用
Expression.Lambda
人
答案 0 :(得分: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()。
答案 1 :(得分: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);
}
}
但我想知道它的效率(性能命中),因为它使用反射..
答案 2 :(得分:1)
您需要使用班级的全名。
例如:
Type.GetType("System.Collections.Generic.Dictionary`2[System.String,[MyType,MyAssembly]]")
答案 3 :(得分:0)
如果从外部装配加载类型,我建议使用Activator.CreateInstanceFrom
。
var typeReference = Activator.CreateInstanceFrom(assemblyPath, fullyQualifiedClassName);
return typeReference.Unwrap() as T;
答案 4 :(得分:0)
如果您希望能够在部署后将业务规则添加为dll并在运行时创建它们,我建议您在应用程序下有一个业务规则文件夹,在该应用程序中加载所有dll,搜索实现IBusinessRules的所有类型在每个dll中使用反射。鉴于您现在拥有类型的句柄,根据名称创建一个句子很容易,您的项目将扩展。
或者将类的程序集限定名传递给您的方法。