4

我们正在为少数客户构建一个应用程序,每个客户都有自己的要求以及类似的要求。我们还希望将所有代码保留在同一个应用程序中,而不是对其进行分支,并且 IF 不是一个好的选择,因为它会遍布各处。

我计划为所有人提供基类。然后每个客户都有自己的类,覆盖方法将在其中执行特殊逻辑。

我们如何在编译时加载程序集而不是这样做

public class BaseClass {
    public string getEventId()
}

public class ClassForJohn:BaseClass {
    [override]
    public string getEventId()
}

public class ClassForAdam:BaseClass {
    [override]
    public string getEventId()
}

void UglyBranchingLogicSomewhere() {
   BaseClass  eventOject;
   if("John"==ConfigurationManager.AppSettings["CustomerName"]){
        eventOject = new ClassForJohn();


   }else if("Adam"==ConfigurationManager.AppSettings["CustomerName"]){
        eventOject = new ClassForAdam();


   }else{
        eventOject = new BaseClass ();

   }
  eventId = eventOject.getEventId();
}
4

6 回答 6

6

这就是我将插件(加载项)加载到我的一个项目中的方式:

const string PluginTypeName = "MyCompany.MyProject.Contracts.IMyPlugin";

/// <summary>Loads all plugins from a DLL file.</summary>
/// <param name="fileName">The filename of a DLL, e.g. "C:\Prog\MyApp\MyPlugIn.dll"</param>
/// <returns>A list of plugin objects.</returns>
/// <remarks>One DLL can contain several types which implement `IMyPlugin`.</remarks>
public List<IMyPlugin> LoadPluginsFromFile(string fileName)
{
    Assembly asm;
    IMyPlugin plugin;
    List<IMyPlugin> plugins;
    Type tInterface;

    plugins = new List<IMyPlugin>();
    asm = Assembly.LoadFrom(fileName);
    foreach (Type t in asm.GetExportedTypes()) {
        tInterface = t.GetInterface(PluginTypeName);
        if (tInterface != null && (t.Attributes & TypeAttributes.Abstract) !=
            TypeAttributes.Abstract) {

            plugin = (IMyPlugin)Activator.CreateInstance(t);
            plugins.Add(plugin);
        }
    }
    return plugins;
}

我假设每个插件都实现IMyPlugin. 您可以根据需要以任何方式定义此接口。如果您遍历插件文件夹中包含的所有 DLL 并调用此方法,则可以自动加载所有可用插件。

通常你至少会有三个程序集:一个包含接口定义,主程序集引用这个接口程序集,至少一个程序集实现(当然也引用)这个接口。

于 2013-02-28T18:52:22.917 回答
4

每个客户都有自己的 exe 和 config 文件,并且有共享的 dll 吗?还是有共享的exe,每个客户都有自己的dll?

您可以将完整的类型名称放在配置中,如下所示:

Shared.exe.config:

<appSettings>
  <add key="CustomerType" value="NamespaceForJohn.ClassForJohn, AssemblyForJohn"/>
</appSettings>

并将AssemblyForJohn.dll放在与Shared.exe相同的文件夹中。

然后你可以像这样在代码中动态加载它:

共享的.exe:

var typeString = ConfigurationManager.AppSettings["CustomerType"];
var parts = typeString.Split(',');
var typeName = parts[0];
var assemblyName = parts[1];
var instance = (BaseClass)Activator.CreateInstance(assemblyName, typeName).Unwrap();
于 2013-02-28T18:48:22.600 回答
3

也许这个例子会有所帮助

public MyInterface GetNewType() { 
       Type type = Type.GetType( "MyClass", true ); 
       object newInstance = Activator.CreateInstance( type ); 
       return newInstance as MyInterface; 
    } 
于 2013-09-24T12:44:49.940 回答
1

这是使用Unity使用 DI 处理它的一种方法。

IUnityContainer container = new UnityContainer();
string customerNamespace = ConfigurationManager.AppSettings["CustomerNamespace"];
container.RegisterType(typeof(ISomeInterface), 
                       Type.GetType(customerNamespace+".SomeImplementation"));


// ...

ISomeInterface instance = conainer.Resolve<ISomeInterface>();

ISomeInterface每个客户在客户特定的命名空间中都有自己的实现。

于 2013-02-28T18:38:20.307 回答
1

您可以通过以下方式从程序集中创建外部类型的实例:

object obj = Activator.CreateInstance( 
    "External.Assembly.Name", "External.Assembly.Name.TypeName");
BaseClass b = (BaseClass) obj;
b.getEventId();

您将存储程序集的名称并在配置文件或其他适当的位置键入。

于 2013-02-28T18:40:00.797 回答
0

我会使用 Unity,但作为一个简单的工厂。

Unity Framework:如何从同一个接口实例化两个类?

你可以存储你的

我正在使用 Unity.2.1.505.2(以防万一)。

  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
  </configSections>


      <unity>
        <container>
          <register type="IVehicle" mapTo="Car" name="myCarKey" />
          <register type="IVehicle" mapTo="Truck" name="myTruckKey" />
        </container>
      </unity>

这是 DotNet 代码。

UnityContainer container = new UnityContainer();

UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
                section.Configure(container);

string myKey = "John";  /* read from config file */ /* with this example, the value should be "myCarKey" or "myTruckKey"  */

IVehicle v1 = container.Resolve<IVehicle>(myKey); 

看:

http://msdn.microsoft.com/en-us/library/ff664762(v=pandp.50).aspx

http://www.sharpfellows.com/post/Unity-IoC-Container-.aspx

于 2013-02-28T20:11:24.650 回答