これを明確にするために、私は動的とMakeGenericTypeを使って作業しています。しかし、私は助けができませんが、これを行う良い方法があると思います。私がしようとしているのは、Unityを使用して「プラグイン」ローダーを作成することです。私はあなたが私がやっていることに対する感覚を得ることができるように、コードを投稿するときにそれを説明します。ジェネリック型のインスタンスを実行時に解決された関数に返す
まず私は、プラグイン自体投稿します。ここで注意すべき
[RegisterAction("MyPlugin", typeof(bool), typeof(MyPlugin))]
public class MyPlugin: IStrategy<bool>
{
public IStrategyResult<bool> Execute(ISerializable info = null)
{
bool result;
try
{
// do stuff
result = true;
}
catch (Exception)
{
result = false;
}
return new StrategyResult<bool>
{
Value = result
};
}
}
カップルの事を。その後
[AttributeUsage(AttributeTargets.Class)]
public sealed class RegisterActionAttribute : Attribute
{
public StrategyAction StrategyAction { get; }
public RegisterActionAttribute(string actionName, Type targetType, Type returnType, params string[] depdencies)
{
StrategyAction = new StrategyAction
{
Name = actionName,
StrategyType = targetType,
ResponseType = returnType,
Dependencies = depdencies
};
}
}
インタフェース:かなりまっすぐ進む
public interface IStrategy<T>
{
IStrategyResult<T> Execute(ISerializable info = null);
}
public interface IStrategyResult<T>
{
bool IsValid { get; set; }
T Value { get; set; }
}
すべての最初のRegisterActionAttributeです。ここでの目標は、クラスがロードされたときにクラスにメタデータを添付することです。ロードは、ファイル検索パターンを使用してbinディレクトリにアセンブリを単にロードするラッパーを使用して単一性を介して行われ、StrategyActionsのコレクションを持つシングルトンクラスに追加されます。私はそれが動作し、アセンブリを登録して解決することを知っているので、私はここにすべての統一コードをペーストする必要はありません。
今質問の肉に。私はアクションを実行するシングルトン上の関数を持っています。これらはUnity.Interception HandlerAttributesに適用し、そのような文字列を渡された(私は、このためのコードを投稿することができますが、私はそれが関連だったとは思いませんでした)されています
[ExecuteAction("MyPlugin")]
ハンドラはシングルトン上で実行次の関数を呼び出しますクラスが登録されている(コレクションに追加されている)関数を「実行する」。
public dynamic Execute(string action, params object[] parameters)
{
var strategyAction = _registeredActions.FirstOrDefault(a => a.Name == action);
if (strategyAction == null)
return null;
var type = typeof (IStrategy<>);
var generic = type.MakeGenericType(strategyAction.StrategyType);
var returnType = typeof (IStrategyResult<>);
var genericReturn = returnType.MakeGenericType(strategyAction.ResponseType);
var instance = UnityManager.Container.Resolve(generic, strategyAction.Name);
var method = instance.GetType().GetMethod("Execute");
return method.Invoke(instance, parameters);
}
この実行は、依存関係やものではありません(下記参照)を管理するためのソート結果のコレクションを返します列挙子コールに包まれています。これらの値は、ISTrategyResult {T}のValueプロパティを使用して呼び出し元によって参照され、他のビジネスルールで定義されたさまざまな処理を行います。
public List<dynamic> ExecuteQueuedActions()
{
var results = new List<dynamic>();
var actions = _queuedActions.AsQueryable();
var sortedActions = TopologicalSort.Sort(actions, action => action.Dependencies, action => action.Name);
foreach(var strategyAction in sortedActions)
{
_queuedActions.Remove(strategyAction);
results.Add(Execute(strategyAction.Name));
}
return results;
}
これはうまくいきましたが、これは機能し、プラグインのRegisterAction属性で指定された戻り値の型を取得します。ご覧のとおり、プラグインのタイプと戻り値の型をキャプチャしています。私は "ジェネリック"変数を使用して、MakeGenericTypeを使用して型を一致させて解決します。これは正常に動作します。また、コレクションの型に基づいて戻り値の型を表すジェネリックを作成しています。
ここで私が気に入らないのは、この値を関数に返すためにdynamicを使用することです。私はIStrategyResult {T}としてこれを返す方法を理解できません。なぜなら、明らかに "動的Execute(...")呼び出し側は実行時に関数の戻り値の型を意味することができないからです。 MakeGenericMethodコールでExecuteを呼び出すのは、実際に期待されるタイプのStrategyActionを持っているからです。コール中にTタイプを決定している間にIStrategyResult {T}の厳密な型付けされた結果を返す方法を見つけることができれば、 。
なぜ私は現在の実装でこれを行うことができないのか理解していますが、私はダイナミックを使わずにこの機能をすべてラップする方法を見つけようとしており、役に立つかもしれないと思っています。これを非ジェネリックなクラスやそれ以外の呼び出しでラップすると、それが唯一の解決策であれば問題ありません。
あなたは一度それを持っていると結果はどうなりますか?結果を扱うための対応する 'IHandler'インタフェースが必要なようです。それで 'Execute'と' Handle'メソッドを 'Action'として構成するだけです。 –
Lee
私は呼び出しの結果を集約するために使用できるラッパー関数を追加しました。うまくいけばあなたの質問に答えます。あるいは、私はあなたの反応を誤解していますか? – Brandon
私はあなたが言っていることを見ていると思います。しかし、私はこれらの値のいくつかを返す必要があることを考えると、私は呼び出し元のTの型を知っているのと同じ問題に遭遇すると思います。私はこれがこのようにすることに固有の問題であることを知っています。私はそれが獣の本質だと思うし、私ができる唯一のことは、結果を適切に処理するために呼び出し側にチェック/キャストを追加することだけです。ダイナミックについての涼しい(しかし危険な)ことは、結果を参照するためにキャストする必要がないということです。しかし、かつては哲学的に "灰色の"領域でダイナミックなものでした。 – Brandon