C# 以类型安全的方式遍历对象层次结构
在工作中,我们有一个非常复杂的数据结构,t复杂:C# 以类型安全的方式遍历对象层次结构,c#,algorithm,types,C#,Algorithm,Types,在工作中,我们有一个非常复杂的数据结构,t复杂: 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
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; }
}
公共类TComplex
{
公共AType AType{get;set;}
公共b类型b类型{get;set;}
公共IList CTypes{get;set;}
}
公共类类型
{
公共int AInteger{get;set;}
public int BInteger{get;set;}
公共字符串AString{get;set;}
}
公共类B类型
{
公共字符串AString{get;set;}
公共IList数据类型{get;set;}
}
公共类CType
{
公共int Id{get;set;}
公共字符串值{get;set;}
}
公共类数据类型
{
公共字符串值{get;set;}
}
最近通过向多个节点类型添加enum 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
{
公共AType AType{get;set;}
公共b类型b类型{get;set;}
公共IList CTypes{get;set;}
}
公共类类型
{
公共int AInteger{get;set;}
public int BInteger{get;set;}
公共字符串AString{get;set;}
公共ParsedValue ParsedValue{get;set;}
}
公共类B类型
{
公共字符串AString{get;set;}
公共IList数据类型{get;set;}
公共ParsedValue ParsedValue{get;set;}
}
公共类CType
{
公共int Id{get;set;}
公共字符串值{get;set;}
公共ParsedValue ParsedValue{get;set;}
}
公共类数据类型
{
公共字符串值{get;set;}
}
首先,给定一个TComplex类型的对象,我如何遍历层次结构并生成ParsedValue的所有值:
public static IEnumerable<ParsedValue> GetParsedValues(TComplex tComplex)
公共静态IEnumerable GetParsedValue(TComplex TComplex)
更进一步,我如何才能将此对象中的所有ParsedValue设置为特定的ParsedValue,例如ParsedValue。显式:
public static IEnumerable<Action<ParsedValue>> SetParsedValues(TComplex tComplex)
公共静态IEnumerable setParsedValue(TComplex TComplex)
我有一个GetParsedValue和SetParsedValue的简单实现。但是,如果要向层次结构中的其他类型添加ParsedValue,则还需要更改GetParsedValue和SetParsedValue的实现,我发现这很脆弱:
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;
}
}
公共静态IEnumerable GetParsedValue(TComplex TComplex)
{
返回tComplex.AType.ParsedValue;
返回tComplex.BType.ParsedValue;
foreach(tComplex.CTypes中的var cType)
{
返回cType.ParsedValue;
}
}
公共静态IEnumerable SetParsedValue(TComplex TComplex)
{
收益率返回值=>tComplex.AType.ParsedValue=value;
收益率返回值=>tComplex.BType.ParsedValue=value;
foreach(tComplex.CTypes中的var cType)
{
收益率返回值=>cType.ParsedValue=value;
}
}
我已经考虑过反射,但是有没有更好的方法呢?要使它更通用,可以让每个类实现一个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;
}
}
公共类TComplex
{
公共AType AType{get;set;}
公共b类型b类型{get;set;}
公共IList CTypes{get;set;}
公共IEnumerable GetParsedValues()
{
foreach(AType.GetParsedValues()中的var parsedValue)
收益率;收益率;
foreach(BType.getParsedValue()中的var parsedValue)
收益率;收益率;
foreach(CTypes中的变量cType)
foreach(cType.GetParsedValues()中的var parsedValue)
收益率;收益率;
}
}
公共类类型
{
公共int AInteger{get;set;}
public int BInteger{get;set;}
公共字符串AString{get;set;}
公共ParsedValue ParsedValue{get;set;}
公共IEnumerable GetParsedValues()
{
收益率;收益率;
}
}
公共类B类型
{
公共字符串AString{get;set;}
公共IList数据类型{get;set;}
公共ParsedValue ParsedValue{get;set;}
公共IEnumerable GetParsedValues()
{
收益率;收益率;
}
}
公共类CType
{
公共int Id{get;set;}
公共字符串值{get;set;}
公共ParsedValue ParsedValue{get;set;}
公共IEnumerable GetParsedValues()
{
收益率;收益率;
}
}
正如您所看到的那样,您可以修改您的类型,只需编辑该类型的函数。我看不出您现在的操作方式有任何令人讨厌的地方,真的,但是如果您愿意,可以稍微清理一下 一种选择可能是为所有类编写一个公共基类
ParsedValueProviderBase
,而不是一个接口。为其提供两种相同方法的虚拟无操作实现:
public virtual IEnumerable<ParsedValue> GetParsedValues()
=> Enumerable.Empty<ParsedValue>();
public virtual IEnumerable<ParsedValue> SetParsedValues(ParsedValue pv)
=> Enumerable.Empty<ParsedValue>();
让每个人都实现这个接口。其中一些可能是这样的:
public IEnumerable<ParsedValue> GetParsedValues()
=> yield return ParsedValue;
public IEnumerable<ParsedValue> SetParsedValues(ParsedValue pv)
=> yield return ParsedValue = pv;
public IEnumerable GetParsedValues()
=>收益率返回解析值;
公共IEnumerable setParsedValue(ParsedValue pv)
=>收益率回报率ParsedValue=pv;
其他人会反复出现在孩子身上,等等
如果您可能在其他类中到处使用该接口,那么这可能是一个好主意。您可以编写接口并在
ParsedValueProviderBase
中实现它 Via reflection OP可以遍历所有属性并查找接口实现。:-)我喜欢这个主意。我能澄清一些事情吗?我是否应该考虑在层次结构中的每一个类型中实现iPaySturyValeType,并返回没有任何PARSEDIVE值的类型的枚举??(?),然后在添加了PARSEDIVE值之后修复实现?@ NVN911,这是一个判断调用。如果你认为有一个公平的机会,你以后会这样做,那么你可以像我们一样
public IEnumerable<ParsedValue> GetParsedValues()
=> yield return ParsedValue;
public IEnumerable<ParsedValue> SetParsedValues(ParsedValue pv)
=> yield return ParsedValue = pv;