工厂 class 使用泛型但没有基础 class

Factory class using generics but without base class

我遇到了一个我认为可能不寻常的问题(我搜索了很多答案,但我认为我没有找到答案)。

我有从队列中读取的消息,并且根据消息类型包含需要反序列化为具体 c# 的负载 class。这需要最终是具体的(我不能一直使用泛型)因为我使用表达式树对从队列到达的 classes 执行评估。

基础 class 看起来像这样:

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

我这样实现基础 class:

 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))
                    {

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

我避免使用 dynamic,但这意味着我将对象作为 object 传递。我更喜欢 而不是 使用 dynamic 但在这种情况下,在 运行 时间投射对象可能不会更好。

我还必须更改代码,以便有一个方法可以执行 Func,而不是返回 Func<T, bool>。这是为了避免引用通用 class。我不确定您在实际实施中是否真的需要 Func

我必须创建一个新的基础 class,它不是通用类型。

// 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 派生(并将一些属性移动到基础 class。

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

具体的class基本相同。我已经实现了自己的 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);
}