是否有任何官方方法可以编写立即调用的函数表达式?

时间:2013-08-16 18:03:27

标签: c#

这样的事情:

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

6 个答案:

答案 0 :(得分:19)

对于真实代码,使其成为一种功能......出于娱乐目的,等同于JavaScript IIFE的C#比Select更直接:

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

答案 1 :(得分:13)

我很惊讶没有人提到这一点,但你可以使用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介绍了local functions。这些不是真正的 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 :(得分:6)

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

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

答案 3 :(得分:4)

这是我的同事提出的:

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

请注意,这是基于阿列克谢的回答。

答案 4 :(得分:1)

也许不是很回答这个问题,但是...我想要用C#进行IIFE的原因之一是要赋予在对象上调用的函数更好的含义。在此示例中,我想说明“点击”方法在测试代码中特定上下文中的作用(我不喜欢注释)。

之前...

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

之后...

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

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

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

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

lastLineForEditing.Click();

这为我解决了IIFE问题,使方法名称具有含义。

答案 5 :(得分:1)

由于某种原因,获取隐式类型的委托确实很困难,但是如果您为其编写自己的静态方法,并不是没有可能。

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

...

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

x = Func.Create(() => {
   // complex logic to create a value
})();