2010-02-26 3 views
2

나는이 코드를 다음 코드 : 필드가 비어 또는 계산 된 하나의 계산 된 값을 사용하여 동일한 값을 할당되어있는 경우계산 된 값을 재정의하는 방법은 무엇입니까? 그래서

private Nullable<decimal> _excessWages; 
public decimal ExcessWages 
{ 
    get 
    { 
     return _excessWages ?? CalculateExcessWages(); 
    } 
    set 
    { 
     if (value != CalculateExcessWages()) 
      _excessWages = value; 
     else 
      _excessWages = null; 
    } 
} 

그래서 기본적으로 내가 구현하기 위해 노력하고있어 행동은 그렇지 않은 것입니다 할당 된 값을 저장하십시오.

여기에는 이와 같은 재정의를 지원해야하는 분야가 많이 있습니다. 이것을 달성하는 가장 좋은 방법입니까? 그렇지 않다면 당신은 무엇을 제안하겠습니까?

+0

실제로 무엇을 요구하고 있습니까? 속성이'virtual'으로 선언되었지만 텍스트에서 setter 내부의 코드 구조에 대해 더 많이 묻습니다. –

+0

죄송합니다. 나는 가상을 제거했다. 내가 관심있는 것이 아닙니다. 최종 사용자의 관점에서 '우선 할 수있는'것에 관심이 있습니다. –

답변

2

나는 대부분 Vlad의 제안에 따라이 약간에 흥분. 밝혀졌습니다 은이를 추상화하기 위해 단일 제네릭 클래스를 사용합니다. 결과는 다음과 같습니다.

public class Overridable<T> 
{ 
    private Func<T> _calculate; 
    private readonly Func<T, T, bool> _compare; 
    protected T _t; 

    public Overridable(Func<T> calculate, Func<T, T, bool> compare) 
    { 
     _calculate = calculate; 
     _compare = compare; 
    } 

    public T Value 
    { 
     get { return _compare(_t, default(T)) ? _calculate() : _t; } 
     set { _t = _compare(value, _calculate()) ? default(T) : value; } 
    } 
} 

유형을 하위 클래스에서 설정할 때까지 알 수 없으므로 비교 위임을 전달해야합니다. 그래서 간단한 ==은 그것을 자르지 않을 것입니다. 쉬운 경로를 가서 Func 대리자를 사용했지만 어떤 이유로 든 .NET 2.0에 맞게 조정해야한다면 일반 대리자로 바꿀 수 있습니다.

null 대신 default(T)을 사용하고 있습니다. 이것은 Nullable<T>의 기본값이 null (또는보다 정확하게는 정의되지 않았지만 동일하게 작동 함)이기 때문에 작동합니다.

nullable 형식에 대해 Overridable<T>을 선언하지 못하게하지 않습니다. 당신이 바람을 피우는 것은 런타임 오류가 아니지만 유용하지는 않습니다. Overridable<decimal>.Valuenull으로 설정하면 컴파일러 오류가 발생합니다. default(decimal)으로 설정하면 값 계산으로 되돌아갑니다.

이 경로는 내가 사용하고있는 클래스의 속성이 결국 XML로 전송 된 직렬화 가능 객체를 채워야하기 때문에 진행되었습니다. xml의 ​​스키마에는 정수, 소수 및 문자열의 혼합으로 정의 된 숫자 필드가 포함됩니다.

당신은 지금처럼 Overriddable 클래스를 사용

private Overridable<decimal?> _excessWages = 
    new Overridable<decimal?>(CalculateExcessWages, (x,y) => x == y); 
public virtual decimal? ExcessWages 
{ 
    get 
    { 
     return _excessWages.Value; 
    } 
    set 
    { 
     _excessWages.Value = value; 
    } 
} 

내가이과에 달렸다 유일한 문제는이 필드 이니셜 라이저에서 사용할 수 없습니다 수 CalculateExcessWages가 비 정적 방법이었다. 내 클래스의 모든 속성이 정적이 아니기 때문에 생성자의 모든 뒷받침 필드를 초기화해야했습니다.

0

내 눈이보기에 적당합니다.

private Nullable<decimal> _excessWages; 
private Nullable<decimal> _excessWagesCalculated; 
public virtual decimal ExcessWages 
{ 
    get 
    { 
     if (_excessWagesCalculated == null) 
      _excessWagesCalculated = CalculateExcessWages(); 
     return _excessWages ?? _excessWagesCalculated; 
    } 
    set 
    { 
     if (_excessWagesCalculated == null) 
      _excessWagesCalculated = CalculateExcessWages(); 
     if (value != _excessWagesCalculated) 
      _excessWages = value; 
     else 
      _excessWages = null; 
    } 
} 

그러나,이 당신보다 더 많은 코드, 그리고 난 당신이 단순화하기 위해 찾고있는 생각 : 캐시 할 비용, 확인을 경우 내가 할 수있는 유일한 변화는 CalculateExcessWages()를 캐시하는 것입니다.

+0

흠, 흥미 롭습니다. 그것은 문제 일 수도 있고 아닐 수도 있습니다. 이러한 오버라이드 가능한 속성의 대부분은 다른 오버 라이드 가능한 속성에서 계산되며 다른 속성 등으로 계산됩니다. 속성은 액세스 할 때마다 또는 변경 될 때마다 계산 체인을 설정합니다. 데이터베이스에서 개체를로드 할 때 사용자가 속성 중 하나를 무시하거나 사용자가 보고서를 인쇄하거나 개체를 serialize 할 때이 상황이 발생합니다. 생각할 게있어. –

1

이 클래스 래퍼를 만들 수 있습니다.

class OverridableValue<T> 
{ 
    public OverridableValue<T>(Func<T> calculator) 
    { 
     _calculator = calculator; 
    } 
    private Nullable<T> _t; 
    private Func<T> _calculator; 
    public T Get() 
    { 
     return return _t ?? _calculator(); 
    } 
    public void Set(T value) 
    { 
     _t = (value != _calculator()) ? value : null; 
    } 
} 

문법적으로 감미롭지는 않지만 적어도 일부 키 스트로크는 저장됩니다.

지금 당신은 다음과 같이 사용할 수 있습니다 :

class Foo 
{ 
    OverridableValue<decimal> _excessWages = 
      new OverridableValue<decimal>(CalculateExcessWages); 
    public decimal ExcessWages 
    { 
     get { return _excessWages.Get(); } 
     set { _excessWages.Set(value); } 
    } 
    ... 
} 

장점은 전체 로직이 클래스에 숨겨져 있다는 것입니다.

+0

모든 재정의 할 수있는 속성이 값 유형이 아니므로이를 수정해야합니다. '_t'에는 nullable이 아닌 모든 유형을 할당 할 수 있습니다. –

+0

당신은 기본적으로 2 개의 제네릭이 필요합니다 : 하나는'where T : class'이고, 하나는 값 타입입니다. – Vlad

1

당신은 편리한 세트를 정의하여이 작업을 수행 할 수/도우미 메서드

private static T GetUtil<T>(ref Nullable<T> value, Func<T> calc) { 
    return value ?? calc(); 
} 

private static void SetUtil<T>(ref Nullable<T> value, T newValue, Func<T> calc) { 
    if (newValue != calc()) { 
    value = newValue 
    } else { 
    value = null; 
    } 
} 

private Nullable<decimal> _excessWages; 
public decimal ExcessWages 
{ 
    get { return GetUtil(ref _excessWages, CalculateExcessWages); } 
    set { SetUtil(ref _excessWages, value CalculateExcessWages); } 
} 
관련 문제