2016-10-10 22 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