C# 动态加载具有相同函数的不同库
我有一个引用外部DLL的程序:C# 动态加载具有相同函数的不同库,c#,reflection,C#,Reflection,我有一个引用外部DLL的程序: magic.externalFunctions.sql.dll 根据目标系统的不同,我可能需要以下内容: magic.externalFunctions.nosql.dll 这些DLL是提供相同功能的外部库。甚至公共方法和属性也是相同的。但是它们没有组合接口或基类 现在,我需要根据目标系统在这两个库之间进行选择。如果他们有一个共同的接口,我会这样做: public class DoDatabaseStuff() { private IMagic _ma
magic.externalFunctions.sql.dll
根据目标系统的不同,我可能需要以下内容:
magic.externalFunctions.nosql.dll
这些DLL是提供相同功能的外部库。甚至公共方法和属性也是相同的。但是它们没有组合接口或基类
现在,我需要根据目标系统在这两个库之间进行选择。如果他们有一个共同的接口,我会这样做:
public class DoDatabaseStuff() {
private IMagic _magic
public DoDatabaseStuff(bool useNoSql) {
if (useNoSql) {
_magic=new SqlMagic();
} else {
_magic=new NoSqlMagic();
}
myTable=_magic.Table.Create("CustomerTable");
myTable.Columns.Add(typeof(int),"ID");
myTable.Columns.Add(typeof(string),"Name");
}
}
有没有办法不使用过多的反射来解决这个问题?我仍然希望使用类似于myTable.Columns.Add()
的东西,而不是tableType.GetMethod(“Add”).Invoke()…
我也不想在csproj中使用不同构建配置的条件。虽然这在理论上是可行的,但每次csproj自动更改(例如nuget软件包更新)时,它都会被分发。当您面临无法更改的糟糕设计时,一个好方法是将该设计保留在代码之外。在这种情况下,这意味着您应该创建外部程序集缺少的公共接口 您可以使用适配器来提供统一的接口,从而将初始设计缺陷排除在代码核心之外 首先为要访问的原始类创建抽象:
public interface IMagic {
ITable CreateTable(string name);
}
public interface ITable {
void AddColumn(Type type, string name);
}
然后提供适配器:
class SqlMagicAdapter : IMagic {
SqlMagic m_innerMagic = new SqlMagic();
ITable CreateTable(string name) {
return new SqlTableAdapter(m_innerMagic.Table.Create(name));
}
}
class SqlTableAdapter : ITable {
SqlTable m_innerTable;
public SqlTableAdapter(SqlTable innerTable) {
m_innerTable = innerTable;
}
void AddColumn(Type type, string name) {
m_innerTable.Columns.Add(type, name);
}
}
class NoSqlMagicAdapter : IMagic {
NoSqlMagic m_innerMagic = new NoSqlMagic();
ITable CreateTable(string name) {
return new NoSqlTableAdapter(m_innerMagic.Table.Create(name));
}
}
class NoSqlTableAdapter : ITable {
NoSqlTable m_innerTable;
public NoSqlTableAdapter(NoSqlTable innerTable) {
m_innerTable = innerTable;
}
void AddColumn(Type type, string name) {
m_innerTable.Columns.Add(type, name);
}
使用工厂方法,您可以返回相应的适配器:
public static class MagicFactory {
public static IMagic GetMagic(bool useNoSql) {
if (useNoSql) {
return new NoSqlMagic();
}
else {
return new SqlMagic();
}
}
}
只有使用工厂返回的抽象,您的核心代码才能保持干净:
public class DoDatabaseStuff() {
private IMagic _magic
public DoDatabaseStuff(bool useNoSql) {
_magic = MagicFactory.GetMagic(useNoSql);
ITable myTable = _magic.CreateTable("CustomerTable");
myTable.AddColumn(typeof(int), "ID");
myTable.AddColumn(typeof(string), "Name");
}
}
另一个优点是,您还可以随时进行任何将来的更改,例如,另一个更新的外部库与以前的库不兼容。您可以轻松地支持这些新功能,而无需更改核心代码。当您遇到无法更改的糟糕设计时,最好的方法是将该设计保留在代码之外。在这种情况下,这意味着您应该创建外部程序集缺少的公共接口 您可以使用适配器来提供统一的接口,从而将初始设计缺陷排除在代码核心之外 首先为要访问的原始类创建抽象:
public interface IMagic {
ITable CreateTable(string name);
}
public interface ITable {
void AddColumn(Type type, string name);
}
然后提供适配器:
class SqlMagicAdapter : IMagic {
SqlMagic m_innerMagic = new SqlMagic();
ITable CreateTable(string name) {
return new SqlTableAdapter(m_innerMagic.Table.Create(name));
}
}
class SqlTableAdapter : ITable {
SqlTable m_innerTable;
public SqlTableAdapter(SqlTable innerTable) {
m_innerTable = innerTable;
}
void AddColumn(Type type, string name) {
m_innerTable.Columns.Add(type, name);
}
}
class NoSqlMagicAdapter : IMagic {
NoSqlMagic m_innerMagic = new NoSqlMagic();
ITable CreateTable(string name) {
return new NoSqlTableAdapter(m_innerMagic.Table.Create(name));
}
}
class NoSqlTableAdapter : ITable {
NoSqlTable m_innerTable;
public NoSqlTableAdapter(NoSqlTable innerTable) {
m_innerTable = innerTable;
}
void AddColumn(Type type, string name) {
m_innerTable.Columns.Add(type, name);
}
使用工厂方法,您可以返回相应的适配器:
public static class MagicFactory {
public static IMagic GetMagic(bool useNoSql) {
if (useNoSql) {
return new NoSqlMagic();
}
else {
return new SqlMagic();
}
}
}
只有使用工厂返回的抽象,您的核心代码才能保持干净:
public class DoDatabaseStuff() {
private IMagic _magic
public DoDatabaseStuff(bool useNoSql) {
_magic = MagicFactory.GetMagic(useNoSql);
ITable myTable = _magic.CreateTable("CustomerTable");
myTable.AddColumn(typeof(int), "ID");
myTable.AddColumn(typeof(string), "Name");
}
}
另一个优点是,您还可以随时进行任何将来的更改,例如,另一个更新的外部库与以前的库不兼容。您可以轻松地支持这些新功能,而无需更改核心代码。为什么要在多个执行相同操作的库之间切换?当然,这是一种低效的方法,而且会增加依赖项的数量。但是,如果需要这样做,您可以始终创建帮助器方法,因此一个方法调用SQL库,另一个方法调用非SQL库创建一个包含基类或接口的程序集,并且只向该程序集引入依赖项。然后可以加载适当的实现程序集。在这些情况下,依赖性注射是一种可行的方法。这里的主要设计缺陷是引入两个独立的程序集。然后,您仍然可以引入一个带有抽象的程序集,并创建两个适配器程序集来引用抽象和相应的外部库。那么你们又有了共同点。您甚至可以在一个程序集中完成所有操作。@Sefe是正确的,不要让他们的设计缺陷永久化。将复杂性抽象出来是一种方法。为什么要在多个做相同事情的库之间切换?当然,这是一种低效的方法,而且会增加依赖项的数量。但是,如果需要这样做,您可以始终创建帮助器方法,因此一个方法调用SQL库,另一个方法调用非SQL库创建一个包含基类或接口的程序集,并且只向该程序集引入依赖项。然后可以加载适当的实现程序集。在这些情况下,依赖性注射是一种可行的方法。这里的主要设计缺陷是引入两个独立的程序集。然后,您仍然可以引入一个带有抽象的程序集,并创建两个适配器程序集来引用抽象和相应的外部库。那么你们又有了共同点。您甚至可以在一个程序集中完成所有操作。@Sefe是正确的,不要让他们的设计缺陷永久化。将复杂性抽象出来是一条出路。