22

像这样的东西:

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 不打算以这种方式使用。但是,是的,还有什么其他方法可以做同样的事情?

4

6 回答 6

24

对于真正的代码,让它成为一个函数......出于娱乐目的,相当于JavaScript IIFE的 C# 比Select

var myObject = new MyClass()
{
   x =((Func<int>)(() => {return 2;}))(),...
于 2013-08-16T18:12:22.467 回答
19

我很惊讶没有人提到这一点,但你可以使用这个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";
    })
};

更新:C#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它共享相同范围的相同方法中声明。

于 2013-08-17T02:00:24.657 回答
5

虽然肯定不是“官方的”,但您可以在构造函数或单独的工厂/构建器方法中使用可选的命名参数:

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 的怪异之处。

也就是说,我不喜欢它。只是提供它作为思考的食物。:)


编辑:我想我会添加一个工厂方法样式,因为您在一个您不能(或不想)更改其构造函数的类上使用它是合理的:

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

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

        return myClass;
    }
}

使用类似的用法(只是调用工厂方法):

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.

于 2013-08-16T18:17:30.623 回答
4

这是我的同事想出的:

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

请注意,这是基于 Alexei 的回答。

于 2013-08-16T18:24:18.397 回答
2

出于某种原因,很难获得隐式类型的委托,但如果您为它编写自己的静态方法,这并非不可能。

public static class Func {
   public static Func<T> Create<T>(
      Func<T> func
   ) =>
     func;       
}

...

x = Func.Create(() => "result")();

x = Func.Create(() => {
   // complex logic to create a value
})();
于 2018-09-29T20:52:45.303 回答
1

也许没有完全回答这个问题,但是......我想要 C# 中的 IIFE 的一个原因是为了给在对象上调用的函数赋予更好的意义。在此示例中,我想说明“Click”方法在测试代码中的特定上下文中的作用(我不喜欢注释)。

前 ...

lastLine.Click(); //click to begin editing line

后 ...

Action<IWebElement> clickToStartEditing = line => line.Click();
clickToStartEditing(lastLine);

后来我发现我可以简单地用另一个名字创建一个新方法......

Action clickToStartEditing = lastLine.Click;
clickToStartEditing(lastLine);

最后简单地以更好的方式命名变量可以更好地解决问题(对我来说)

lastLineForEditing.Click();

这为我解决了一个 IIFE 问题,为方法名称赋予了意义。

于 2018-08-22T10:54:28.340 回答