2009-07-17 2 views
0

다른 개체의 속성과 DataValue이라는 개체를 가지고 있지만 DataValue을 반환하려는 유형은 다른 속성의 개체에 포함 된 정보에 따라 다릅니다. 내 길을 확신하는 것이 최선의 방법입니다.올바른 데이터 형식이 반환되지 않을 수있는 디자인 문제

저는 AssetStructure라는이 비즈니스 객체를 가지고 있습니다.

AssetStructure 개체에는 기본적으로 해당 필드에 보관할 수있는 데이터, 특정 데이터 형식의 기본값 및 일부 표시 정보 속성에 대한 정보가 들어있는 일련의 개체 인 IAssetStructureField 개체의 일반 목록이 들어 있습니다. IAssetStructureField 인터페이스를 구현하는 각 객체는 다른 데이터 유형을 보유합니다. 예를 들어, DefaultValue의 유형은 string 일 수 있고 다른 유형은 List<ofCustomType> 일 수 있습니다.

AssetDataField라는 일반 개체 목록을 포함하는 내 Asset 개체가 있습니다. AssetDataField에는 AssetStructureField를 포함하는 속성과 DataValue, 즉 해당 StructureField에 대한 자산 데이터가 포함 된 속성이 있습니다.

내 문제는 AssetDataField DataValue 속성의 데이터 형식이므로 AssetStructureField 개체의 세부 정보에 따라 달라질 필요가 있습니다. 이 StructureField는 Asset (데이터 유형 List<UserGroups>)에 대한 액세스 권한이있는 모든 사용자 그룹을 나타내는 데이터를 보유 할 수 있으며 또 다른 하나는 설명 필드 (데이터 유형 문자열) 일 수 있으므로 AssetDataField에서 나오는 DataValue가 동일한 유형이어야합니다.

내가 지금하고있는 일 중에서 생각하고있는 것, 그리고 아마도 훨씬 더 잘 수행 할 수 있다고 생각하는 것은 AssetDataField.DataValue 객체를 반환하고 AssetDataField.StructureField.DefaultValue의 typeof로 캐스팅하는 것입니다.

object fieldValue; 
object fieldDefaultValue; 
Asset certainAsset = new Asset(32423); 
foreach (AssetDataField dataField in certainAsset.DataFields) 
{ 
    fieldDefaultValue = datafield.StructureField.DefaultValue; 
    fieldValue = datafield.DataValue as typeof(fieldDefaultValue); 

    // then do stuff depending on what typeof(fieldValue) is. This is where I 
    // see things getting particularly ugly. Not only just because that 
    // this class here will need to know the possible types that may be 
    // returned, so it can deal. 

    if (typeof(fieldValue) == whatever) 
    { 
      // deal; 
    } 
    else if (typeof(fieldValue) == whatever2) 
    { 
      // deal differently; 
    } 
} 

누구에게 의견이 있습니까? 나는 완전한 재실행을 반대하지 않는다. 정말 오래간만해서 죄송합니다. 상황을 잘 설명하려고했습니다. 도와 주려는 UML 다이어그램을 만들려고했지만 ArgoUML이 작동하고있었습니다. 귀하가 제공 할 수있는 모든 통찰력에 감사드립니다.

+0

어리 석음 때문에 명확성을 제공하려는 시도가 끔찍하게 실패 했습니까? – Billyhole

답변

0

AssetDataField를 추상 기본 클래스로 설정하고 다른 클래스를 파생시켜 작업을 수행해야하는 것처럼 보입니다. 예 :

class Program 
{ 
    static void Main(string[] args) 
    { 
     Asset certainAsset = new Asset(32423); 
     foreach (AssetDataField dataField in certainAsset.DataFields) 
     { 
      dataField.Deal(); 
     } 
    } 
} 

class Asset 
{ 
    public List<AssetDataField> DataFields = new List<AssetDataField>(); 
    public Asset(int id) 
    { 
     // Load asset #id 
     if (id == 32423) 
     { 
      DataFields.Add(new AssetDataFieldString()); 
      DataFields.Add(new AssetDataFieldFloat()); 
     } 
    } 
} 

abstract class AssetDataField 
{ 
    public AssetDataField() 
    { 
     FieldValue = DefaultValue; 
    } 

    public abstract object DefaultValue { get; } 
    public abstract object FieldValue { get; set; } 
    public abstract void Deal(); 
} 

abstract class AssetDataFieldType<T> : AssetDataField 
{ 
    protected T internalValue; 
    public override object FieldValue 
    { 
     get 
     { 
      return TypedValue; 
     } 
     set 
     { 
      TypedValue = (T)System.Convert.ChangeType(value, typeof(T)); 
     } 
    } 

    public virtual T TypedValue 
    { 
     get 
     { 
      return internalValue; 
     } 
     set 
     { 
      internalValue = value; 
     } 
    } 
} 

class AssetDataFieldString : AssetDataFieldType<string> 
{ 
    public override object DefaultValue 
    { 
     get { return "Default String"; } 
    } 

    // Optionally override TypedValue 

    public override void Deal() 
    { 
     Console.WriteLine(TypedValue.PadLeft(20)); 
    } 
} 

class AssetDataFieldFloat : AssetDataFieldType<float> 
{ 
    public override object DefaultValue 
    { 
     get { return 0; } 
    } 

    // Optionally override TypedValue 

    public override void Deal() 
    { 
     Console.WriteLine(TypedValue.ToString("#0.000")); 
    } 
} 
0

참고 : 이는 EAV 기반 시스템을 쿼리 한 결과와 유사합니다. 메타 데이터가 이러한 종류의 시스템의 백본과 같은 방식으로 코드를 참조하는 코드는 컴파일 타임에 액세스하는 유형 (따라서 유형)을 파악하려고 노력해야합니다. 단순히 표시하고자하는 경우에는 데이터를 표시하는 데 상관없이이 종류의 것이 필요합니다.

C#은 정적으로 입력되므로 동일한 '슬롯'(변수, 배열 위치)에 '다른 것들'을 넣을 수 없으므로 C#이 모두 '1'을 차지하는 올바른 '모양'이 아니면 C#이 정적으로 입력됩니다. 이것을 위해 현재 C#에서 사용할 수있는 유일한 슬롯은 object입니다. 이것은 작동하지만 상자에 모든 값 유형 (2)을 지정합니다.

C# 4.0에서는 동적 인 것을 사용할 수 있습니다. 동적 인 것은 객체 아래에 있지만 컴파일러가 객체를 통해 합법적이라고 생각하지 않더라도 원하는 모든 메소드를 호출 할 수있게 해줍니다.

모든 유형이 공통 인터페이스를 공유하는 경우 객체를 피하고 유용한 의미를 얻을 수 있습니다 (예 : double Sum(double d)이 처리중인 모든 인스턴스에 대해 의미있는 연산 인 경우 유용한 결과가 나올 수 있음).그러나 현재 존재하는 유형을 제어하지 않는 것처럼 들리므로 유용한 인터페이스에 부합 할 수있는 기회가 없습니다.

가능한 유형 집합이 다루기 쉬운 경우 아래 기술 된 기술이 작동하지만 여전히 성가시다.

그런 다음 가능하면 정적으로 입력 할 수 있지만 이전 코드와 비슷한 것으로 작동 할 수 있습니다. 안전하지 않은 코드 또는 적어도 노동 조합 (전용 구조체)없이

Asset certainAsset = new Asset(32423); 
foreach (IGeneralValue dataField in certainAsset.DataFields) 
{ 
    object fieldValue = datafield.Value; 
    Type fieldType = dataField.GetValueType();  

    if (typeof(double).Equals(fieldType)) 
    { 
     double d = ((double)fieldValue); 
    } 
    else if (typeof(string).Equals(fieldType)) 
    { 
     string d = ((string)fieldValue); 
    } 
    else if (typeof(whatever).Equals(fieldType)) 
    { 
     // deal with whatever 
    } 
    else 
    { 
     // the safe option 
     throw new NotSupportedException(fieldType +" is not supported!"); 
    } 
} 
  1. .
  2. 이는 성능뿐 아니라 int를 이중으로 unbox 할 수 없습니다. unboxed 인스턴스에서 작동하는 변환에도 불구하고.
관련 문제