【问题标题】:C# Variable = new function () {};C# 变量 = 新函数 () {};
【发布时间】:2012-08-26 01:33:54
【问题描述】:

在 C# 中是否可以动态创建新函数来定义变量?

我知道

string getResult() {
    if (a)
        return "a";
    return "b";
}
String result = getResult();

是可能的,但我正在寻找类似的东西

String result = new string getResult() {
    if (a)
        return "a";
    return "b";
}

这可能吗?如果是这样,有人会演示吗?

编辑 有可能

编辑:最终 - 解决方案

这是我野蛮入侵的最终结果

Func<string> getResult = () =>
{
    switch (SC.Status)
    {
        case ServiceControllerStatus.Running:
            return "Running";
        case ServiceControllerStatus.Stopped:
            return "Stopped";
        case ServiceControllerStatus.Paused:
            return "Paused";
        case ServiceControllerStatus.StopPending:
            return "Stopping";
        case ServiceControllerStatus.StartPending:
            return "Starting";
        default:
            return "Status Changing";
    }
};

TrayIcon.Text = "Service Status - " + getResult();

【问题讨论】:

    标签: c# function variables


    【解决方案1】:

    定义此类函数的一种方法:

    Func<bool, string> getResult = ( a ) => {
        if (a)
            return "a";
        return "b";
    }
    

    然后您可以调用:string foo = getResult( true );。作为委托,它可以在需要时被存储/传递和调用。

    例子:

    string Foo( Func<bool, string> resultGetter ){
        return resultGetter( false );
    }
    

    您还可以close 围绕范围内的变量:

    bool a = true;
    
    Func<string> getResult = () => {
        if (a)
            return "a";
        return "b";
    }
    
    string result = getResult();
    

    【讨论】:

    • (如果我理解提问者的意图...)我建议不要这样做,因为它不是 Funcs 通常用于的用途,并且会让您代码的未来读者感到困惑(包括你自己)更熟悉正常的Func 使用模式。除非它真的是 FuncAction 更有意义的实例,否则内联代码或使其成为单独的方法。
    • 我不同意。虽然我不知道 OP 的需求是什么并且这是一个人为的示例,但定义和重复/有条件/最终执行委托的能力既强大又常见。但这只是我。
    • 正如 Tim S. 所说,这对我来说并不适用。如果我要使用这条路线,我宁愿在单独的方法中定义它。我这样做的唯一真正目的是像 Actionscript 那样在一行中定义它懒惰的风格,或者我认为在 Java 中也是可能的。在意识到它可能比我最初的预期更难时,我很好奇它是如何实现的,如果它真的可以实现的话。
    • 你可以在一行中定义一个委托,但如果这是唯一的动机,它可能不合适。
    • 如果我想在每次调用 getResult 时传递 ServiceController(我的开关在上下文中构建的对象),那么上面提到的初始方法会起作用。 “getResult(服务控制器);”本来可以的,但我不想那样做,看着你回答的那部分让我失望了。我现在看到你说你可以在范围内关闭变量。这实际上正是我想要的。很抱歉没有早点注意到。
    【解决方案2】:

    您想使用内联 if 语句。

    string result = a ? "a" : "b";
    

    【讨论】:

    • 我觉得这可行,但我实际上是在尝试实现一个开关。为了便于理解,我将其简化为代码中的 if 语句。是否有内联 switch 语句?
    • 你可以用Dictionary来做到这一点。
    • Dictionary 比简单的 switch 语句(相对而言)产生更多的开销。您通常应尽量避免将字典用于编译时已知的逻辑。
    【解决方案3】:

    如果你真的想要内联,你可以为 String 类型创建一个扩展方法:

    static class StringExtensions {
        public static string ExecuteFunc(
                this string str, 
                Func<string, string> func
            ) {
            return func(str);
        }
    }
    

    然后,当你想使用它时,你可以这样做:

    string str = "foo";
    
    string result = str.ExecuteFunc( s => {
            switch(s){
                case "a":
                    return "A";
                default:
                    return "B";
            }
        }
    );
    

    【讨论】:

    • +1 用于使用扩展。虽然它并没有真正传递功能。不能一次性赋值,每次调用都必须赋值。
    【解决方案4】:

    不确定您的示例中变量 a 的范围是什么,但假设它在该范围内是可访问的(就像您的示例中一样):

    Func<string> getResult = () =>
    {
        return a ? "a" : "b";
    }
    

    【讨论】:

    • Action&lt;T&gt;s 不返回任何内容;你的意思是Func&lt;string&gt;?无论如何,我认为var 可能会工作......
    • @minitech, var 不适用于 lambda。没有足够的上下文让编译器知道如何理解它。 (编译器错误是“无法将 lambda 表达式分配给隐式类型的局部变量”)
    • @TimS.:您认为它可以智能地确定返回类型。哦,好吧。
    • @minitech 或者你可以让 ReSharper 将函数提取为变量并智能地确定返回类型:)
    • @minitech 根本原因(或者我推断)是FuncAction 在 C# 编译器中没有任何特殊地位——它们只是代表。如果您定义了一个具有相同签名的委托,它怎么知道您希望它是哪个?例如。即使在非常常见的内置委托中,Action&lt;object, EventArgs&gt;EventHandler 也是相同的。
    【解决方案5】:

    根据您发布的解决方案,这里有一个更好的方法。

    更改您的 ServiceControllerStatus 枚举以添加 [Description] 属性:

    public enum ServiceControllerStatus
    {
        [Description("Running")]
        Running,
        // ... others
    }
    

    在新的静态类中添加以下扩展方法:

    public static string ToDescription(this Enum value)
    {
        var attributes = (DescriptionAttribute[])value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
        return attributes.Length > 0 ? attributes[0].Description : value.ToString();
    }
    

    现在你可以简单地写:

    TrayIcon.Text = "Service Status - " SC.Status.ToDescription();
    

    【讨论】:

      猜你喜欢
      • 2021-09-22
      • 2020-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-19
      • 2017-10-20
      相关资源
      最近更新 更多