Могут ли свойства внутри инициализатора объекта ссылаться друг на друга?

Возможно ли, чтобы свойства ссылались друг на друга во время создания динамического объекта анонимно типизированного объекта (т.е. внутри инициализатора объекта)? В приведенном ниже упрощенном примере необходимо повторно использовать свойство Age без повторного тяжелого вызова GetAgeFromSomewhere(). Конечно, это не работает. Любое предложение о том, как это сделать?

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

Возможно или невозможно что-то подобное с динамическими объектами инициализаторами анонимно типизированных объектов?


person user3199179    schedule 18.04.2015    source источник
comment
Заранее присвойте результат GetAgeFromSomewhere переменной в отдельном операторе.   -  person Theodoros Chatzigiannakis    schedule 18.04.2015
comment
Эта проблема также не связана напрямую с динамическими типами, а с инициализаторами.   -  person CSharpie    schedule 18.04.2015
comment
@CSharpie Используя статически объявленный тип, OP мог бы просто сделать IsLegal производным свойством: public bool IsLegal { get { return Age > 18; } }   -  person Theodoros Chatzigiannakis    schedule 18.04.2015
comment
Зная о создании переменной для значения, но я хочу избежать создания дюжины переменных в реальном сценарии. Любые другие идеи?   -  person user3199179    schedule 18.04.2015
comment
Каков ваш реальный сценарий? Вы можете объяснить в своем вопросе, когда / зачем вам это нужно   -  person Alex    schedule 18.04.2015
comment
Re: использование вами термина динамические объекты: в объектах, которые вы создаете, нет ничего динамического. Они просто имеют анонимный тип, который компилятор генерирует для вас. за кулисами. Возможно, лучше не использовать здесь слово «динамический», потому что его легко перепутать с ключевым словом dynamic и DLR (что совсем другое).   -  person stakx - no longer contributing    schedule 18.04.2015
comment
спасибо stakx, обновленный вопрос!   -  person user3199179    schedule 18.04.2015
comment
@ user3199179: Кажется, мы оба редактировали одновременно, и наши правки столкнулись. Кажется, моя версия победила. Я надеюсь, что вы согласны с этим; в противном случае отредактируйте снова, я останусь. :)   -  person stakx - no longer contributing    schedule 18.04.2015


Ответы (3)


К сожалению, это невозможно даже с явно типизированными объектами. Это связано с тем, как работают инициализаторы объектов. Например:

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

Выдает эту ошибку компилятора в «IsLegal»:

Ошибка 1. Инициализатор поля не может ссылаться на нестатическое поле, метод или свойство MyClass.Age...

Инициализатор поля не может ссылаться на другие нестатические поля, а поскольку анонимные типы не создают статических полей, вы не можете использовать значение одного поля для инициализации другого. Единственный способ обойти это — объявить переменные вне анонимного типа и использовать их внутри инициализатора.

int age = GetAgeFromSomewhere(id);
var profile = new {
  Age = age,
  IsLegal = age > 18
};
person Ron Beyer    schedule 18.04.2015

Не усложняй, будь проще

//Create a variable
var age = GetAgeFromSomewhere(id);
var profile = new {
  Age = age,
  IsLegal = age>18
}
person Satpal    schedule 18.04.2015
comment
спасибо, но ищу другое решение, если это возможно, не создавая дюжину переменных в моем реальном сценарии - person user3199179; 18.04.2015
comment
@ user3199179, затем создайте нормальный класс и объявите производные свойства. - person Satpal; 18.04.2015
comment
Я спрашиваю о динамических объектах - person user3199179; 18.04.2015

То, что вы хотите, невозможно в инициализаторах объектов. Вы не можете прочитать свойства инициализируемого объекта. (Не имеет значения, является ли тип анонимным или нет.)

Вместо этого создайте класс

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> (начиная с 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);
person Olivier Jacot-Descombes    schedule 18.04.2015
comment
Поскольку вы упомянули слово «ленивый» во втором блоке кода, почему бы не упростить код с помощью Lazy<int>? private readonly Lazy<int> age = new Lazy<int>(() => GetAgeFromSomewhere(_id)); public int Age { get { return age.Value; } }. - person stakx - no longer contributing; 18.04.2015
comment
Я добавил заявление об инициализаторах объектов и анонимных типах, а также пример использования Lazy<T>. Обратите внимание, что в C# есть ключевое слово dynamic для объявления динамических объектов, и использование этого термина в другом контексте может привести к путанице. Здесь вы говорите об анонимных типах new { ... }. - person Olivier Jacot-Descombes; 18.04.2015
comment
Обратите внимание, что тип, созданный с помощью new { ... }, является анонимным, т. Е. У него нет публичного имени (поэтому у него есть внутреннее имя, известное компилятору); однако он создается во время компиляции (а не во время выполнения) и поэтому является статическим, а не динамическим. Также обратите внимание, что объект, созданный таким образом, является строго типизированным, т. е. известно, что он имеет этот очень анонимный тип во время компиляции, и каждое из свойств типа также является статически типизированным. (Если вы присвоите выражение типа dynamic одному из его свойств, это свойство будет статически типизировано как dynamic!) - person Olivier Jacot-Descombes; 19.04.2015