嵌套使用C#Object Initializers

时间:2009-04-27 22:00:15

标签: c# c#-3.0

所以,对象初始化器是各种方便的 - 特别是如果你正在做linq,它们是完全必要的 - 但我无法弄明白这个:

public class Class1 {
   public Class2 instance;
}

public class Class2 {
   public Class1 parent;
}

像这样使用:

Class1 class1 = new Class1();
class1.instance = new Class2();
class1.parent = class1;

作为初始化程序:

Class1 class1 = new Class1() {
    instance = new Class2() {
        parent = class1
    }
};

这不起作用,class1应该是一个未分配的局部变量。当你做像

这样的事情时,它在Linq中变得更加棘手
select new Class1() { ...

它甚至没有名称来引用它!

我该如何解决这个问题?我可以简单地使用对象初始化器来制作嵌套引用吗?

6 个答案:

答案 0 :(得分:7)

  

我可以简单地使用对象初始化器来制作嵌套引用吗?

你是对的 - 你做不到。会有一个循环; A需要B进行初始化,但B需要A之前。确切地说 - 您当然可以创建嵌套对象初始值设定项,但不能使用循环依赖关系。

但你可以 - 如果可能的话,我会建议你 - 按照以下方式解决这个问题。

public class A
{
   public B Child
   {
      get { return this.child; }
      set
      {
         if (this.child != value)
         {
            this.child = value;
            this.child.Parent = this;
         }
      }
   }
   private B child = null;
}

public class B
{
   public A Parent
   {
      get { return this.parent; }
      set
      {
         if (this.parent != value)
         {
            this.parent = value;
            this.parent.Child = this;
         }
      }
   }
   private A parent = null;
}

在属性中构建关系有一个好处,如果你忘记了一个初始化语句,就不能得到一个不一致的状态。很明显,这是一个次优的解决方案,因为你需要两个语句来完成一件事。

b.Parent = a;
a.Child = b;

使用属性中的逻辑,只需一个语句即可完成任务。

a.Child = b;

或者反过来说。

b.Parent = a;

最后使用对象初始化器语法。

A a = new A { Child = new B() };

答案 1 :(得分:2)

使用对象初始化器无法做到这一点。但是,你可以使用propery代码来实现这个技巧:

class A
{
    B b;

    public B B
    {
        set
        {
            b = value;
            b.a = this;
        }
        get
        {
            return b;
        }
    }
}

class B
{
    public A a;
}

致电:

var a = new A  {  B = new B() };

答案 2 :(得分:1)

此问题并非特定于对象初始值设定项,它是C#语言的一般限制。在明确分配之前,您不能使用局部变量。这是一个更简单的复制品

Class1 Foo(Class1 c1) {
  return c1;
}

void Example() {
  Class1 c1 = Foo(c1);
}

答案 3 :(得分:1)

我认为无论如何都要解决这个问题,当应用程序实例化Class1对象时,它需要首先创建Class2对象,以便它知道引用所在的内存位置。如果您尝试以下操作,可以看到这一点:

        Class1 myClass1 = null;

        myClass1 = new Class1()
        {
            instance = new Class2
            {
                parent = myClass1
            }
        };

这将编译并运行,但Class2的parent属性将为null,因为这是代码内部行运行时的值,这意味着最内部的行是第一个被执行的行。 / p>

答案 4 :(得分:0)

你当然可以使用嵌套对象初始化器,我一直这样做。

但是,在您的特定情况下,您的对象具有循环引用。您需要在将其分配给另一个之前完成实例化。否则,您正在为编译器处理一个它无法处理的经典chicken and egg problem

答案 5 :(得分:0)

你的例子没有反映出好的班级设计,IMO;这是不恰当的凝聚力,并创建一个循环引用。这就是不可能在一个表达式中将它们一起实例化的原因。

我建议你回到绘图板并将你的课程重构为父/子关系。我在子类上使用构造函数注入,并让子进程告诉父进程它是它的子进程。

例如:

public class ParentClass 
{
    public List<ChildClass> Children;
    public void AddChild(ChildClass child)
    {
        Children.Add(child);
        // or something else, etc. 
    }
    // various stuff like making sure Children actually exists before AddChild is called
}

public class ChildClass 
{
    public ParentClass Parent;
    public ChildClass(ParentClass parent)
    {
        Parent = parent;
        Parent.AddChild(this);
    }
}

然后,在您的主叫代码中:

var parent = new ChildClass(new ParentClass()).Parent;

而且,是的,这在LINQ中起作用:

// qry, etc.
select new ChildClass(new ParentClass()).Parent
  

但是我怎么做所有的   ChildClass具有相同的ParentClass   实例? - Andy Hohorst

然后你必须提前知道父类。

var parent = new ParentClass();
var child = new ChildClass(parent);

var parent = new ParentClass();
// qry, etc.
select new ChildClass(parent)