Существуют ли какие-либо официальные способы написания выражения, вызванного немедленным вызовом?

Что-то вроде этого:

var myObject = new MyClass()
{
    x = " ".Select(y =>
    {
        //Do stuff..
        if (2 + 2 == 5)
            return "I like cookies";
        else if (2 + 2 == 3)
            return "I like muffins";
        //More conditions...
        else
            return "I'm a bitter old man";
    })
};

Я понимаю, что Select не предназначен для использования таким образом. Но да, какие еще способы сделать то же самое?

Ответы

Ответ 1

Я удивлен, что никто не упомянул об этом, но вы можете использовать класс Lazy<T>:

var myObject = new MyClass()
{
    x = new Lazy<string>(() =>
    {
        //Do stuff..
        if (2 + 2 == 5)
            return "I like cookies";
        else if (2 + 2 == 3)
            return "I like muffins";
        //More conditions...
        else
            return "I'm a bitter old man";
    }).Value // <-- Evaluate the function here
};

В качестве альтернативы, если вы хотите не указывать тип возвращаемого значения в любом месте (как вы это делаете с new Lazy<string>, потому что конструкторы не поддерживают вывод типа), вы можете реализовать простой общий метод, подобный этому:

public static T Eval<T>(Func<T> func)
{
    return func();
}

И тогда вы можете позвонить следующим образом:

var myObject = new MyClass()
{
    x = Eval(() =>
    {
        //Do stuff..
        if (2 + 2 == 5)
            return "I like cookies";
        else if (2 + 2 == 3)
            return "I like muffins";
        //More conditions...
        else
            return "I'm a bitter old man";
    })
};

Обновление: С# 7 вводит локальные функции. На самом деле это не IFFE, но они могут решить множество связанных вопросов. Например:

var myObject = new MyClass()
{
    x = GetX()
};

string GetX() {
    //Do stuff..
    if (2 + 2 == 5)
        return "I like cookies";
    else if (2 + 2 == 3)
        return "I like muffins";
    //More conditions...
    else
        return "I'm a bitter old man";
}

Ключевым моментом здесь является то, что GetX может быть объявлен в рамках того же метода, что и myObject, используя тот же объем, что и он.

Ответ 2

Для реального кода сделать его функцией... Для развлекательных целей эквивалент С# JavaScript IIFE более прямой, чем Select:

var myObject = new MyClass()
{
   x =((Func<int>)(() => {return 2;}))(),...

Ответ 3

Хотя, конечно, не "официальный", вы можете использовать необязательные именованные параметры в конструкторе или отдельный метод factory/builder:

public class MyClass
{
   public string x { get; private set; }

   public MyClass(Func<string> x = null)
    {
        if (x != null)
            this.x = x();
    }
}

с использованием:

var myClass = new MyClass(
        x: () =>
            {
                //Do stuff..
                if (2 + 2 == 5)
                    return "I like cookies";
                else if (2 + 2 == 3)
                    return "I like muffins";
                //More conditions...
                else
                    return "I'm a bitter old man";
            }
    );

    Console.WriteLine(myClass.x); //"I'm a bitter old man"

Итак, это не точный синтаксис, который вы запрашивали, но довольно близко и пропускает странность LINQ.

Тем не менее, мне это не нравится. Просто предлагая это как пищу для размышлений.:)


EDIT: Я решил, что добавлю стиль метода factory, поскольку это правдоподобно, что вы используете это в классе, который вы не можете (или не хотите) изменить его конструктор:

public static class MyFactory
{
    public static MyClass CreateMyClass(Func<string> x = null)
    {
        var myClass = new MyClass()

        if (x != null)
                myClass.x = x();

        return myClass;
    }
}

С аналогичным использованием (просто вызывая метод factory):

var myClass = MyFactory.CreateMyClass(
    x: () =>
        {
            //Do stuff..
            if (2 + 2 == 5)
                return "I like cookies";
            else if (2 + 2 == 3)
                return "I like muffins";
            //More conditions...
            else
                return "I'm a bitter old man";
        }
);

РЕДАКТОР: И эй, пока мы на нем. Почему бы не уйти с глубокого конца и сделать это с помощью отдельного строителя и оскорбить неявных операторов!

public class MyClassBuilder
{
    public Func<string> x { get; set; }

    public static implicit operator MyClass(MyClassBuilder builder)
    {
        var myClass = new MyClass();

        if (builder.x != null)
            myClass.x = builder.x();

        return myClass;
    }
}

С использованием, например:

MyClass myClass = new MyClassBuilder
{
    x = () =>
        {
            //Do stuff..
            if (2 + 2 == 5)
                return "I like cookies";
            else if (2 + 2 == 3)
                return "I like muffins";
            //More conditions...
            else
                return "I'm a bitter old man";
        }
};

Итак, теперь синтаксис идентичен, за исключением того, что вы должны явно вводить свой экземпляр вместо использования var.

Ответ 4

Вот что наш коллега придумал:

var myObject = new { 
    x = new Func<int>(() => {return 2;})() 
};

Обратите внимание, что это основано на ответе Алексея.