2016-10-10 3 views
4

Ive는 비정상적인 문제 일 수 있다고 생각합니다 (Ive는 답을 찾기 위해 많이 찾았지만 Ive는 하나를 찾은 것 같아요).제네릭을 사용하지만 기본 클래스가없는 팩토리 클래스

대기열에서 읽은 메시지가 있고 메시지 유형에 따라 구체적인 C# 클래스로 직렬화가 필요없는 페이로드가 포함되어 있습니다. 표현식 트리를 사용하여 대기열에서 도착한 클래스에 대한 평가를 수행하기 때문에 결과적으로 구체적이어야합니다 (전체적으로 제네릭을 사용할 수 없습니다).

는 기본 클래스는 다음과 같습니다 : 다음 호출 같은 것을 할

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

기본 유형을 구현하는 모든 유형을 deserialize해야합니다 (메시지가 도착할 때까지 어떤 유형인지 알지 못합니다). UiTransactionUpdate는 다양한 구현 중 하나입니다. 특정 유형의 메소드가 더 있고 deserialize가 나쁜 예일 수 있습니다. 그러나 해결하고자하는 문자열을 기반으로 유형을 instanciating하는 프로세스입니다. – 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

great 물건을! 시간을 넣어 작동 대답을 주셔서 감사합니다. 내 질문에서 꽤 많은 실제 코드를 밖으로, 그래서 당신의 제안을 포함하도록 약간의 리팩터링 할 필요가 있지만 구현 한 후 모두 작동했습니다. 또한 - BaseBase 대신 SimpleRuleMessageBase를 선택했습니다. :) – KerSplosh

관련 문제