2017-05-31 61 views
0

我一直在努力获得一个演员工作的类具有自己的集合。在使用List中具有两个TypeA元素的根对象进行测试时,当List执行隐式转换时...它将输入集合的TypeA元素的转换代码,并且因为这是树的顶部,所以返回TypeAIntermediate无需进入foreach循环(即完美 - SomeAs中没有任何内容)。但是当它返回转换的实例时,它似乎重新开始在根的转换代码的顶部,就像什么都没有发生。c#转换运算符为递归集合类

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

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

我没有看到这段代码如何创建一个无限循环。你能用简化的代码重现问题吗?如果是的话,你是否可以包含构建'TypeA'类的代码,当你尝试转换它时会进入无限循环?此代码示例中也没有任何地方递归。 – juharr

+0

我认为隐式强制转换发生在children.Add(item)(从TypeA项到Children )强制转换运算符再次调用自己以执行隐式强制转换将计为递归。而且,你怎么称呼一个拥有自身成员的类,或者自己的成员集合(可能不是递归的 - 实际上好奇)? –

+0

您没有'TypeA'集合,您有'TypeB'集合。如果你确实有一个正在被转换的'TypeA'的集合,那么你将会有递归,如果两个对象都拥有另一个或者它们本身在集合中,你可以得到一个无限循环。 – juharr

回答

0

下面是如何编写该方法以避免堆栈溢出,如果您的层次结构中存在环路。

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对象在这种情况下,你不需要再次创建它,只是返回相应TypeAIntermediate参考。如果它没有,那么你创建一个新的TypeAIntermediate并填充它的集合递归调用Create方法,也需要字典。

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

+0

所以我可以确认我们只对这个类的三个实例进行操作。根和另外两个(均具有空的TypeA列表),它们位于根目录的TypeA列表中。我也确认转换操作符只在一个地方被调用,首先通过注释掉在操作符中仍然存在断点的线条(未到达),然后重新启用这条线在演员身上有一个突破点。它只能达到一次。 ...但奇怪的循环行为持续在转换代码中。 –

+0

我想我必须真正开始尝试简化的代码。为了回答你的问题,不,我没有试图用这个版本的代码(但它与真实的东西非常相似)。我只是希望有人能立即认识到这个问题。它自己收藏的根本是一个很好的电话 - 我希望你能拥有它。 –

+0

所以......我在一个空白的项目中构建了原始的简化代码......它运行良好。我想我的项目中有一些陌生人正在进行。 ...根据发布的代码,我的问题不会有成功的答案(因为我猜测它的工作原理),所以也许这个转换循环检测器的东西对其他人有用。谢谢。 –