工厂类使用泛型但没有基类

时间:2016-10-10 13:20:14

标签: c# abstract-class factory-pattern

我得到了我认为可能是一个不寻常的问题(我已经搜索了很多答案,但我不认为我找到了一个)。

我有从队列中读取的消息,并且根据消息类型包含需要反序列化为具体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))
                    {

我真正想知道的是如何创建一个工厂(或者我可以吗?)能够以这样的方式定义基类的实现:我可以返回一个用于表达式树的具体类评估,而不必重复每种类型的所有调用代码。

1 个答案:

答案 0 :(得分: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);
}

更新了BaseRuleMessage以从BaseBaseRuleMessage派生(并将一些属性移至基类。

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