2016-10-10 46 views
4

我得到了我認爲可能是一個不尋常的問題(我已經搜索了很多答案,但我不認爲我找到了一個)。工廠類使用泛型,但沒有基類

我有從隊列中讀取的消息,並根據消息類型包含需要反序列化到具體的c#類的有效載荷。這需要最終是具體的(我不能使用泛型),因爲我使用表達式樹對從隊列到達的類執行評估。

的基類看起來是這樣的:

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))); 
    } 

我實現的基類是這樣的:

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; } 

然後我做這樣的事情打電話:

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只是許多不同實現中的一種。還有更多的方法是類型特定的,反序列化可能是一個不好的例子,但它是基於我感興趣解決的字符串實例化類型的過程。 – 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); 
} 

更新了BaseRuleMessageBaseBaseRuleMessage導出(和移動中的一些屬性的基類。

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

很大。所以我不得不做一些重構來包含你的建議,但是在實現它們之後,所有的工作都已經完成了如預期的那樣。另外 - 我選擇了SimpleRuleMessageBase而不是BaseBase :) – KerSplosh