Are there any official ways to write an Immediately Invoked Function Expression?

后端 未结 6 1392
自闭症患者
自闭症患者 2021-02-04 02:21

Something like this:

var myObject = new MyClass()
{
    x = \" \".Select(y =>
    {
        //Do stuff..
        if (2 + 2 == 5)
            return \"I like c         


        
相关标签:
6条回答
  • 2021-02-04 02:33

    While certainly not "official", you could use optional named parameters in the constructor or a separate factory/builder method:

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

    with usage like:

    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"
    

    So, it's not the exact syntax you were asking for, but pretty close and skips the LINQ weirdness.

    That said, I don't like it. Just offering it as food for thought. :)


    EDIT: I figured I'd add a factory method style since it's plausible you're using this on a class that you can't (or don't want to) change its constructor:

    public static class MyFactory
    {
        public static MyClass CreateMyClass(Func<string> x = null)
        {
            var myClass = new MyClass()
    
            if (x != null)
                    myClass.x = x();
    
            return myClass;
        }
    }
    

    With similar usage (just calling a factory method instead):

    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";
            }
    );
    

    EDIT: And hey, while we're at it. Why not go off the deep end and do it with a separate builder and abuse implicit operators!

    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;
        }
    }
    

    With usage like:

    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";
            }
    };
    

    So now the syntax is identical, except you have to explicitly type your instance instead of using var.

    0 讨论(0)
  • 2021-02-04 02:37

    I'm surprised no one's mentioned this yet, but you could use the Lazy<T> class:

    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
    };
    

    Alternatively, if you want to avoid having to specify the return type anywhere (as you do with new Lazy<string> because constructors do not support type inference), you can implement a simple generic method like this:

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

    And then you can call like this:

    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";
        })
    };
    

    Update: C#7 introduces local functions. These are not really IFFEs, but they may solve a variety of related issues. For example:

    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";
    }
    

    The key here is that GetX can be declared within the same method as myObject share the same scope as it.

    0 讨论(0)
  • 2021-02-04 02:38

    For real code make it a function... For entertainment purposes C# equivalent of JavaScript IIFE is more direct than Select:

    var myObject = new MyClass()
    {
       x =((Func<int>)(() => {return 2;}))(),...
    
    0 讨论(0)
  • 2021-02-04 02:44

    Maybe not quite answering the question but ... one reason I wanted IIFE in C# was to give better meaning to a function being called on an object. In this example I wanted to give meaning as to what the 'Click' method does in a particular context within test code (and I do not like comments).

    Before ...

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

    After ...

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

    Later I discovered I could simply create a new method with another name ...

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

    Finally simply naming the variable in a better way can better solve the issue (for me)

    lastLineForEditing.Click();
    

    This solved an IIFE issue for me, to give meaning to the method name.

    0 讨论(0)
  • 2021-02-04 02:51

    For some reason it's really hard to get implicitly typed delegates, but it's not impossible if you write your own static methods for it.

    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
    })();
    
    0 讨论(0)
  • 2021-02-04 02:53

    Here is what my coworker came up with:

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

    Note that this is based Alexei's answer.

    0 讨论(0)
提交回复
热议问题