以类型安全的方式行走对象层次结构

时间:2016-12-21 16:49:54

标签: c# algorithm types

在工作中,我们有一个非常复杂的数据结构,TComplex:

result: Object

最近通过向多个节点类型添加枚举ParsedValue进行了修改。

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类型的对象,我将如何走分层次结构并产生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; }   
}

更进一步,我怎样才能将此对象中的所有ParsedValues设置为特定的ParsedValue ,比如ParsedValue.Explicit:

public static IEnumerable<ParsedValue> GetParsedValues(TComplex tComplex)

我有一个天真的GetParsedValues和SetParsedValues实现。但是,如果我要向层次结构中的其他类型添加ParsedValue,那么我还需要更改GetParsedValues和SetParsedValues的实现,我发现它很脆弱:

public static IEnumerable<Action<ParsedValue>> SetParsedValues(TComplex tComplex)

我考虑过反思,但还有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

我现在没有看到任何关于你现在这样做的非常令人反感的事情,但是如果你愿意,你可以稍微清理一下。

一个选项可能是为所有类而不是接口编写公共基类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中实现它。

答案 1 :(得分:1)

为了使这更通用,您可以让每个类实现一个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;
    }
}

正如您可以看到的那样,您可以修改类型并只编辑该类型的功能。