具有递归集合的 class 的 c# 转换运算符

c# conversion operator for class with recursive collection

我一直在努力让一个演员为一个拥有自己的集合的 class 工作。在用列表中有两个 TypeA 元素的根对象进行测试时,当列表进行隐式转换时...它输入集合中 TypeA 元素的转换代码,因为这是树的顶部,returns TypeAIntermediate 不进入 foreach 循环(完美 - SomeAs 中没有任何内容)。但是当它 returns 转换后的实例时,它似乎从根的转换代码的顶部重新开始,就像什么都没发生一样。

据我所知,这永远不会停止。我重写了这个遵循相同格式的简化版本...希望我没有搞砸。

//These are models used in a .Net 4.5 EF6 Library 
public class TypeA
{
    public string TypeAStuff;
    public TypeB JustOneB;
    public List<TypeA> SomeAs;


    public static implicit operator TypeAIntermediate(TypeA a)
    {
        //New up an Intermediate A to return.
        TypeAIntermediate aI = new TypeAIntermediate();
        //And get ready to do handle the collection... a few ways to do this.
        List<TypeAIntermediate> children = new List<TypeAIntermediate>();

        //...but this appears to create an infinite loop?
        foreach (TypeA item in a.SomeAs)
            children.Add(item); //Cast from TypeA to to TypeAIntermediate happens here but will just keeps cycling

        aI.TypeAStuff = a.TypeAStuff;
        aI.JustOneB = a.JustOneB;
        aI.SomeAs = children;
        return aI;
    }
}

public class TypeB
{
    public string TypeBStuff;

    public static implicit operator TypeBIntermediate(TypeB b)
    {
        TypeBIntermediate bI = new TypeBIntermediate();
        bI.TypeBStuff = b.TypeBStuff;
        return bI;
    }
}

//These Intermediate Classes live in a .Net35 Library - Unity cannot use Libraries compiled for later .Net Versions.
public class TypeAIntermediate
{
    public string TypeAStuff;
    public TypeBIntermediate JustOneB;
    public List<TypeAIntermediate> SomeAs;
}

public class TypeBIntermediate
{
    public string TypeBStuff;
}

如果您的层次结构中有循环,您可以通过以下方式编写代码以避免堆栈溢出。

public static implicit operator TypeAIntermediate(TypeA a)
{
    return Convert(a, new Dictionary<TypeA, TypeAIntermediate>());
}

private static TypeAIntermediate Convert(
    Type A a, 
    Dictionary<TypeA, TypeAIntermediate> lookup)
{
    TypeAIntermediate aI;
    if(lookup.TryGetValue(a, out aI))
    {
        return aI;
    }

    aI = new TypeAintermediate();
    lookup.Add(a, aI);

    List<TypeAIntermediate> children = new List<TypeAIntermediate>();
    foreach (TypeA item in a.SomeAs)
        children.Add(Convert(item, lookup)); 

    aI.TypeAStuff = a.TypeAStuff;
    aI.JustOneB = a.JustOneB;
    aI.SomeAs = children;
    return aI;
}

基本上,通过使用字典,您可以确定是否有任何 TypeA 对象已经为它创建了一个 TypeAIntermediate 对象,在这种情况下您不需要再次创建它,只需 return对应的TypeAIntermediate引用。如果还没有,那么您创建一个新的 TypeAIntermediate 并填充它的集合递归调用 Create 方法,该方法也采用字典。

此外,如果您在不同的分支中两次引用相同的对象,这只会创建一个 TypeAIntermediate 引用,而不是两个。