このインターフェースを考えると:
public interface ILoanCalculator
{
decimal Amount { get; set; }
decimal TermYears { get; set; }
int TermMonths { get; set; }
decimal IntrestRatePerYear { get; set; }
DateTime StartDate { get; set; }
decimal MonthlyPayments { get; set; }
void Calculate();
}
そしてそれの2つの実装:
namespace MyCompany.Services.Business.Foo
{
public interface ILoanCalculator : Common.ILoanCalculator
{
}
public class LoanCalculator : ILoanCalculator
{
public decimal Amount { get; set; }
public decimal TermYears { get; set; }
public int TermMonths { get; set; }
public decimal IntrestRatePerYear { get; set; }
public DateTime StartDate { get; set; }
public decimal MonthlyPayments { get; set; }
public void Calculate()
{
throw new NotImplementedException();
}
}
}
namespace MyCompany.Services.Business.Bar
{
public interface ILoanCalculator : Common.ILoanCalculator
{
}
public class LoanCalculator : ILoanCalculator
{
public decimal Amount { get; set; }
public decimal TermYears { get; set; }
public int TermMonths { get; set; }
public decimal IntrestRatePerYear { get; set; }
public DateTime StartDate { get; set; }
public decimal MonthlyPayments { get; set; }
public void Calculate()
{
throw new NotImplementedException();
}
}
}
上記の単純なコードを考えると、Calculate メソッドの実装は会社ごとに異なるとしましょう。初期化中にアセンブリをロードし、正しいアセンブリの正しいメソッドを呼び出す適切な方法は何ですか? 簡単な部分は、リクエストがどの会社に対するものかを判断することであることがわかりました。現在のビジネスに対応する正しいメソッドを呼び出す必要があるだけです。
ありがとう、スティーブン
サンプルコードの更新
@Scottに大声で叫びます。受け入れられた回答が正しく機能するために必要な変更を次に示します。
この場合、自分の型を見つけるために Assembly Resolver を使用する必要がありました。属性を使用してアセンブリをマークしたため、属性に基づくフィルタリングがより簡単になり、エラーが発生しにくくなりました。
public T GetInstance<T>(string typeName, object value) where T : class
{
// Get the customer name from the request items
var customer = Request.GetItem("customer") as string;
if (customer == null) throw new Exception("Customer has not been set");
// Create the typeof the object from the customer name and the type format
var assemblyQualifiedName = string.Format(typeName, customer);
var type = Type.GetType(
assemblyQualifiedName,
(name) =>
{
return AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetCustomAttributes(typeof(TypeMarkerAttribute), false).Any()).FirstOrDefault();
},
null,
true);
if (type == null) throw new Exception("Customer type not loaded");
// Create an instance of the type
var instance = Activator.CreateInstance(type) as T;
// Check the instance is valid
if (instance == default(T)) throw new Exception("Unable to create instance");
// Populate it with the values from the request
instance.PopulateWith(value);
// Return the instance
return instance;
}
マーカー属性
[AttributeUsage(AttributeTargets.Assembly)]
public class TypeMarkerAttribute : Attribute { }
プラグイン アセンブリでの使用
[assembly: TypeMarker]
最後に、修飾名をサポートするための静的 MyTypes へのわずかな変更
public static class MyTypes
{
// assemblyQualifiedName
public static string LoanCalculator = "SomeName.BusinessLogic.{0}.LoanCalculator, SomeName.BusinessLogic.{0}, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null";
}