C#对象初始值设定项的嵌套使用

C#对象初始值设定项的嵌套使用,c#,c#-3.0,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; 作为初始

因此,对象初始值设定项非常方便——特别是如果你在做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() { ...
它甚至连一个名字都没有


我该怎么做?我可以不使用对象初始值设定项进行嵌套引用吗?

这个问题不是对象初始值设定项特有的,它是C语言中的一般限制。在明确指定局部变量之前,不能使用它。这里有一个更简单的程序

Class1 Foo(Class1 c1) {
  return c1;
}

void Example() {
  Class1 c1 = Foo(c1);
}
我可以不使用对象初始值设定项进行嵌套引用吗

你是对的,你不能。会有一个循环;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() };

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

        Class1 myClass1 = null;

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

这将编译并运行,但Class2的父属性将为null,因为这是代码内行运行时的值,这意味着最内行是第一个要执行的行。

您当然可以使用嵌套对象初始值设定项,我一直都这样做


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

对象初始值设定项不能这样做。但是,您可以使用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() };

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);
    }
}
是的,这在LINQ是有效的:

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

但是我怎么才能把所有的 子类具有相同的父类 实例?–安迪·霍霍斯特

那么您必须提前知道父类

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


但是,我如何使所有的子类都具有相同的父类实例呢?这不是鸡和蛋的问题,至少不是我如何理解初始值设定项的问题:只是声明一个对象并设置其属性的语法糖。对不起,根据对对象初始值设定项的解释,它“不应该”是一个。创建第一个对象,然后为其参数指定值。因为我可以用对象初始化器应该编译到的风格来做这件事,所以我应该可以用对象初始化器来做。我最喜欢这个答案,但它不适合我,因为我忽略了类2实际上是列表,以便让示例更清楚。糟了,结果适得其反。
var parent = new ParentClass();
var child = new ChildClass(parent);
var parent = new ParentClass();
// qry, etc.
select new ChildClass(parent)