简体   繁体   English

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

[英]c# conversion operator for class with recursive collection

I've been struggling to get a cast to work for a class that has a collection of itself. 我一直在努力让演员为一个有自己收藏的班级工作。 In testing with a root object that has two TypeA elements in the List, when the List does the implicit cast... it enters the conversion code for the TypeA element of the collection, and because this is the top of the tree, returns TypeAIntermediate without entering the foreach loop (that perfect - there's nothing in SomeAs). 在使用在List中具有两个TypeA元素的根对象进行测试时,当List执行隐式转换时...它输入集合的TypeA元素的转换代码,并且因为这是树的顶部,所以返回TypeAIntermediate没有进入foreach循环(完美 - SomeAs中没有任何内容)。 But when it returns the converted instance, it appears to start over at the top of the conversion code for the root like nothing happened. 但是当它返回转换后的实例时,它似乎从根目录转换代码的顶部开始,就像没有发生任何事情一样。

As far as I can tell this never stops. 据我所知,这永远不会停止。 I rewrote this simplified version that follows the same format... hopefully I didn't mess up. 我重写了这个简化版本,遵循相同的格式...希望我没有搞砸。

//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;
}

Here's how you can write that to avoid stack overflow if you have loops in your hierarchy. 如果您的层次结构中有循环,则可以使用以下命令来避免堆栈溢出。

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;
}

Basically by using a dictionary you can determine if any TypeA object already has a TypeAIntermediate object created for it in which case you don't need to create it again and just return the corresponding TypeAIntermediate reference. 基本上,通过使用字典,您可以确定是否有任何TypeA对象已经TypeAIntermediate创建了TypeAIntermediate对象,在这种情况下,您不需要再次创建它,只返回相应的TypeAIntermediate引用。 If it hasn't then you create a new TypeAIntermediate and populate it's collection be recursively calling the Create method that also takes the dictionary. 如果没有,那么你创建一个新的TypeAIntermediate并填充它的集合,递归调用也接受字典的Create方法。

Additionally if you have the same object reference twice in different branches this will only create one TypeAIntermediate reference instead of two. 此外,如果在不同分支中有两次相同的对象引用,则只会创建一个TypeAIntermediate引用而不是两个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM