2016-10-10 2 views
4

Iveは異常な問題であると思っています(Iveは答えのためにたくさん検索しますが、Iveは1つを見つけたとは思わない)。ジェネリックを使用しているが、基底クラスを持たないファクトリクラス

私はキューから読み込まれたメッセージを持っています。メッセージタイプに応じて、具体的なC#クラスにデシリアライズする必要のあるペイロードが含まれています。 Expression Treeを使用してキューから到着したクラスの評価を実行するため、最終的に具体的にする必要があります(全般的にジェネリックを使用することはできません)。

は、基底クラスは次のようになります。私は、呼び出すために、このような何かを

public class UiTransactionUpdate : BaseRuleMessage<UiTransactionUpdate> 
{ 

    public override Func<UiTransactionUpdate, bool> CompileRule(Rule r, UiTransactionUpdate msg) 
    { 
     var expression = Expression.Parameter(typeof(UiTransactionUpdate)); 
     Expression expr = BuildExpr(r, expression, msg); 
     return Expression.Lambda<Func<UiTransactionUpdate, bool>>(expr, expression).Compile(); 
    } 
    public Guid TransactionId { get; set; } 

    public Guid GroupId { get; set; } 

    public decimal StatusValue { get; set; } 

public abstract class BaseRuleMessage<T> 
{ 
    public abstract Func<T, bool> CompileRule(Rule r, T msg); 

    public T Deserialize(ClientEventQueueMessage message) 
    { 
     return JsonConvert.DeserializeObject<T>(message.Payload); 
    }   

    public BaseRuleMessage() 
    { 
     RulesCompleted = new List<int>(); 
    } 

    public IEnumerable<Rule> FilterRules(RuleGroup ruleGroup) 
    { 
     return ruleGroup.Rules.Where(item => 
      !RulesCompleted.Any(r => r.Equals(item.Id))); 
    } 

私はこのような基本クラスを実装

switch (message.MessageType) 
      { 
       case "UI_UPDATE": 
       { 
        message.Payload = RemoveNullGroupIdReference(jsonPayload, message.Payload); 
        var deserializedMessage = new UiTransactionUpdate().Deserialize(message); 
        deserializedMessage.RulesCompleted = deserializedMessage.RulesCompleted ?? new List<int>(); 

        foreach (var rule in deserializedMessage.FilterRules(ruleGroup)) 
        { 

を何私は本当に知りたいのですが、どのようにして工場を作ることができますか?(またはできますか?)ベースclの実装を定義するには私の表現ツリーの評価に使う具体的なクラスを各タイプのすべての呼び出しコードを繰り返さなくても返すことができるようにしてください。

+2

なぜ、「デシリアライズ」はインスタンスメソッドであり、静的メソッドではないのですか?あなたは何を実際にデシリアライズしていますか?私は 'UiTransactionUpdate'を想定していました。 –

+0

まず、具体的なクラスにマップされた型フィールド - >を使って、まず思い浮かぶのは動的です。あるいは、多くのメッセージパッシングライブラリは、あなたのために特定の型への逆シリアル化を処理します。 –

+0

基本型が実装している型を逆シリアル化する必要があります(メッセージが到着するまでの型はわかりません)。UiTransactionUpdateはさまざまな実装の1つに過ぎません。型固有のものと非直列化するものがありますが、悪い例かもしれませんが、解決に興味のある文字列に基づいて型をインスタンス化するプロセスです。 – KerSplosh

答えて

2

私はdynamicの使用を避けましたが、これはオブジェクトをobjectとして渡したことを意味しました。 を使用してdynamicを使用することをお勧めしますが、この場合、実行時にオブジェクトをキャストすることはあまり良くない可能性があります。

また、Func<T, bool>を返す代わりに、Funcを実行するメソッドがあるようにコードを変更する必要がありました。これは、汎用クラスの参照を避けるためです。実際の実装でFuncが実際に必要かどうかはわかりません。

一般的に入力されていない新しい基本クラスを作成する必要がありました。

// Horrible name, do change it to something more appropriate 
public abstract class BaseBaseRuleMessage 
{ 
    public IList<int> RulesCompleted { get; set; } 

    public IEnumerable<Rule> FilterRules(RuleGroup ruleGroup) 
    { 
     return ruleGroup.Rules.Where(item => 
       !RulesCompleted.Any(r => r.Equals(item.Id))); 
    } 

    public BaseBaseRuleMessage DeserializeToBaseBaseRuleMessage(ClientEventQueueMessage message) 
    { 
     return (BaseBaseRuleMessage) DeserializeToType(message); 
    } 

    protected abstract object DeserializeToType(ClientEventQueueMessage message); 

    public abstract bool ExecuteRule(Rule rule, object msg); 
} 

BaseBaseRuleMessageから派生しBaseRuleMessageを更新しました(基本クラスにいくつかのプロパティを移動する。

public abstract class BaseRuleMessage<T> : BaseBaseRuleMessage 
    where T : BaseRuleMessage<T> 
{ 
    public abstract Func<T, bool> CompileRule(Rule r, T msg); 

    protected override object DeserializeToType(ClientEventQueueMessage message) 
    { 
     return JsonConvert.DeserializeObject(message.Payload, typeof(T)); 
    } 

    protected BaseRuleMessage() 
    { 
     RulesCompleted = new List<int>(); 
    } 

    public override bool ExecuteRule(Rule rule, object msg) 
    { 
     var message = (T) msg; 
     if (message == null) 
     { 
      throw new InvalidOperationException(); 
     } 
     return CompileRule(rule, message).Invoke(message); 
    } 
} 

具象クラスは基本的に同じである。私が確認するためにBuildExpr私自身を実装しましたコードはコンパイルでき

public class UiTransactionUpdate : BaseRuleMessage<UiTransactionUpdate> 
{ 
    public override Func<UiTransactionUpdate, bool> CompileRule(Rule r, UiTransactionUpdate msg) 
    { 
     var expression = Expression.Parameter(typeof(UiTransactionUpdate)); 
     Expression expr = BuildExpr(r, expression, msg); 
     return Expression.Lambda<Func<UiTransactionUpdate, bool>>(expr, expression).Compile(); 
    } 

    public Guid TransactionId { get; set; } 

    public Guid GroupId { get; set; } 

    public decimal StatusValue { get; set; } 

    private Expression BuildExpr(Rule rule, ParameterExpression parameterExpression, UiTransactionUpdate message) 
    { 
     var transactionIdProperty = Expression.Property(parameterExpression, "TransactionId"); 
     var value = Expression.Constant(rule.TransactionId); 

     return Expression.Equal(transactionIdProperty, value); 
    } 
} 

がそれを使用するには:。

var messageTypeToTypeMap = new Dictionary<string, Func<BaseBaseRuleMessage>> 
{ 
    {"UI_UPDATE",() => new UiTransactionUpdate()} 
}; 

var factoryFunc = messageTypeToTypeMap[message.MessageType]; 
message.Payload = RemoveNullGroupIdReference(jsonPayload, message.Payload); 
var ruleMessage = factoryFunc.Invoke(); 
var deserializedMessage = ruleMessage.DeserializeToBaseBaseRuleMessage(message); 
deserializedMessage.RulesCompleted = deserializedMessage.RulesCompleted ?? new List<int>(); 

foreach (var rule in deserializedMessage.FilterRules(ruleGroup)) 
{ 
    var isTrue = deserializedMessage.ExecuteRule(rule, deserializedMessage); 
} 
+0

私の質問から実際のコードのかなりの部分を除外しましたので、私はあなたの提案を含めるためにリファクタリングを少ししなければならなかったが、実装した後、彼らはすべて働いたまた、私はBaseBaseの代わりに 'SimpleRuleMessageBase'を選択しました:) – KerSplosh

関連する問題