对象初始值设定项中的属性可以相互引用吗?

Can properties inside an object initializer reference each other?

在创建 动态对象 匿名类型对象(即在对象初始值设定项中)期间,属性是否可能以某种方式相互引用?我下面的简化示例需要重用 Age 属性 而无需再次调用 GetAgeFromSomewhere()。当然不行。关于如何实现这一点有什么建议吗?

var profile = new {
  Age = GetAgeFromSomewhere(id),
  IsLegal = (Age>18)
};

对于动态对象匿名类型的对象初始值设定项,这样的事情可能还是不可能?

不要把事情复杂化,保持简单

//Create a variable
var age = GetAgeFromSomewhere(id);
var profile = new {
  Age = age,
  IsLegal = age>18
}

你想要的在对象初始化器中是不可能的。您无法读取正在初始化的对象的属性。 (无所谓,类型是否匿名。)

相反,创建 class

public class Profile
{
    public Profile(int id)
    {
        Age = GetAgeFromSomewhere(id);
    }

    public int Age { get; private set; }
    public int IsLegal { get { return Age > 18; } }
}

或者以懒惰的方式获取年龄:

public class Profile
{
    private readonly int _id;

    public Profile(int id)
    {
        _id = id;
    }

    private int? _age;
    public int Age {
        get {
            if (_age == null) {
                _age = GetAgeFromSomewhere(_id);
            }
            return _age.Value;
        }
    }

    public int IsLegal { get { return Age > 18; } }
}

或使用 Lazy<T> class(从 Framework 4.0 开始):

public class Profile
{
    public Profile(int id)
    {
       // C# captures the `id` in a closure.
        _lazyAge = new Lazy<int>(
            () => GetAgeFromSomewhere(id)
        );
    }

    private Lazy<int> _lazyAge;
    public int Age { get { return _lazyAge.Value; } }

    public int IsLegal { get { return Age > 18; } }
}

这样称呼它

var profile = new Profile(id);

不幸的是,这是不可能的,即使是明确类型化的对象。这是因为对象初始化器的工作方式。例如:

public class MyClass
{
    public int Age = 10;
    public bool IsLegal = Age > 18;
}

在 "IsLegal" 处产生此编译器错误:

Error 1 A field initializer cannot reference the non-static field, method, or property 'MyClass.Age' ...

字段初始值设定项不能引用其他非静态字段,并且由于匿名类型不创建静态字段,您不能使用一个字段的值来初始化另一个字段。解决这个问题的唯一方法是在匿名类型之外声明变量并在初始化程序中使用它们。

int age = GetAgeFromSomewhere(id);
var profile = new {
  Age = age,
  IsLegal = age > 18
};

如果你不想有不必要的变量,我建议你改用当前对象:

var profile = new
{
    Age = GetAgeFromSomewhere(id),
};

profile.IsLegal = profile.Age > 18;