[英]Walking object hierarchy in a typesafe manner
在工作中,我們有一個非常復雜的數據結構TComplex:
public class TComplex
{
public AType AType { get; set; }
public BType BType { get; set; }
public IList<CType> CTypes { get; set; }
}
public class AType
{
public int AInteger { get; set; }
public int BInteger { get; set; }
public string AString { get; set; }
}
public class BType
{
public string AString { get; set; }
public IList<DType> DTypes { get; set; }
}
public class CType
{
public int Id { get; set; }
public string Value { get; set; }
}
public class DType
{
public string Value { get; set; }
}
最近通過將枚舉ParsedValue添加到幾種節點類型進行了修改。
public enum ParsedValue
{
Parsed,
Interpreted,
Guessed,
Explicit
}
public class TComplex
{
public AType AType { get; set; }
public BType BType { get; set; }
public IList<CType> CTypes { get; set; }
}
public class AType
{
public int AInteger { get; set; }
public int BInteger { get; set; }
public string AString { get; set; }
public ParsedValue ParsedValue { get; set; }
}
public class BType
{
public string AString { get; set; }
public IList<DType> DTypes { get; set; }
public ParsedValue ParsedValue { get; set; }
}
public class CType
{
public int Id { get; set; }
public string Value { get; set; }
public ParsedValue ParsedValue { get; set; }
}
public class DType
{
public string Value { get; set; }
}
首先,給定類型為TComplex的對象,我將如何遍歷層次結構並產生ParsedValue的所有值:
public static IEnumerable<ParsedValue> GetParsedValues(TComplex tComplex)
更進一步,我如何將這個對象中的所有ParsedValues設置為特定的ParsedValue ,比如說ParsedValue.Explicit:
public static IEnumerable<Action<ParsedValue>> SetParsedValues(TComplex tComplex)
我有一個天真的GetParsedValues和SetParsedValues實現。 但是,如果要向層次結構中的其他類型添加ParsedValue,則還需要更改GetParsedValues和SetParsedValues的實現,但我發現它們很脆弱:
public static IEnumerable<ParsedValue> GetParsedValues(TComplex tComplex)
{
yield return tComplex.AType.ParsedValue;
yield return tComplex.BType.ParsedValue;
foreach(var cType in tComplex.CTypes)
{
yield return cType.ParsedValue;
}
}
public static IEnumerable<Action<ParsedValue>> SetParsedValues(TComplex tComplex)
{
yield return value => tComplex.AType.ParsedValue = value;
yield return value => tComplex.BType.ParsedValue = value;
foreach(var cType in tComplex.CTypes)
{
yield return value => cType.ParsedValue = value;
}
}
我考慮過反射,但是有更好的方法嗎?
實際上,我看不到任何令人反感的方式,但是如果您願意的話,可以稍微清理一下。
一種選擇是為所有類而不是接口編寫通用基類ParsedValueProviderBase
。 為它提供相同兩種方法的虛擬無操作實現:
public virtual IEnumerable<ParsedValue> GetParsedValues()
=> Enumerable.Empty<ParsedValue>();
public virtual IEnumerable<ParsedValue> SetParsedValues(ParsedValue pv)
=> Enumerable.Empty<ParsedValue>();
子類可以覆蓋或不覆蓋它們。
您還可以編寫一個IParsedValueThing
接口,該接口由部分或全部類實現:
public interface IParsedValueThing {
IEnumerable<ParsedValue> GetParsedValues();
IEnumerable<ParsedValue> SetParsedValues(ParsedValue pv);
}
讓大家實現該接口。 其中一些就是這樣:
public IEnumerable<ParsedValue> GetParsedValues()
=> yield return ParsedValue;
public IEnumerable<ParsedValue> SetParsedValues(ParsedValue pv)
=> yield return ParsedValue = pv;
其他人會遞歸給孩子,等等。
如果您可能在這些類之外的其他所有地方都使用該接口,那可能是個好主意。 您可以編寫接口並在ParsedValueProviderBase
實現它。
為了使這個更通用,您可以讓每個類實現一個GetParsedValues和SetParsedValues函數,在您的復雜類型中,您現在可以依賴這些函數的實現,並確保它們返回您想要中繼的內容。
在這里,我僅實現了GetParsedValues部分,同樣可以應用於SetParsedValues
public class TComplex
{
public AType AType { get; set; }
public BType BType { get; set; }
public IList<CType> CTypes { get; set; }
public IEnumerable<ParsedValue> GetParsedValues()
{
foreach (var parsedValue in AType.GetParsedValues())
yield return parsedValue;
foreach (var parsedValue in BType.GetParsedValues())
yield return parsedValue;
foreach (var cType in CTypes)
foreach (var parsedValue in cType.GetParsedValues())
yield return parsedValue;
}
}
public class AType
{
public int AInteger { get; set; }
public int BInteger { get; set; }
public string AString { get; set; }
public ParsedValue ParsedValue { get; set; }
public IEnumerable<ParsedValue> GetParsedValues()
{
yield return ParsedValue;
}
}
public class BType
{
public string AString { get; set; }
public IList<DType> DTypes { get; set; }
public ParsedValue ParsedValue { get; set; }
public IEnumerable<ParsedValue> GetParsedValues()
{
yield return ParsedValue;
}
}
public class CType
{
public int Id { get; set; }
public string Value { get; set; }
public ParsedValue ParsedValue { get; set; }
public IEnumerable<ParsedValue> GetParsedValues()
{
yield return ParsedValue;
}
}
如您所見,可以修改類型並只編輯該類型的功能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.