【问题标题】:Is it possible to pass interpolated strings as parameter to a method?是否可以将插值字符串作为参数传递给方法?
【发布时间】:2015-08-13 11:42:08
【问题描述】:

我已经开始使用Interpolated Strings(C# 6 的新特性)了,它真的很好用又优雅。但是根据我的需要,我必须将字符串格式作为参数传递给方法。类似下一个:

MyMethod(string format)

过去,我是这样用的:

MyMethod("AAA{0:00}")

现在我尝试了这段代码:

MyMethod($"AAA{i:00}")

但这不起作用,因为i 是在方法内部创建的,并且超出了此上下文的范围。

是否可以使用任何技巧将内插字符串作为参数传递给方法?

【问题讨论】:

    标签: c# string-interpolation c#-6.0


    【解决方案1】:

    您不能这样做,这也不是一个好主意 - 这意味着您正在使用其他方法的局部变量。
    这将违背此功能的目的 - 使 编译器可验证 字符串插值和绑定到局部变量。

    C# 有几个不错的选择。例如,使用Func

    public void MyMethod(Func<int,string> formatNumber)
    {
        int i = 3;
        var formatted = formatNumber(i);
    }
    

    用作:

    MyMethod(number => $"AAA{number:00}");
    

    这比您现在拥有的要好 - 您拥有格式字符串及其在不同地方的用法。

    如果您有多个变量,这种方法可以扩展,但考虑将它们分组到一个类(或结构)中 - func 看起来会更好,并且您的代码将更具可读性。这个类也可以覆盖.ToString(),这可能对你有用。

    另一个简单的选项是只传递格式:MyMethod("00")i.ToString(format),但这仅适用于您可能简化的示例。

    【讨论】:

    • 我将此答案标记为最合理。但我不会使用这个解决方案。我试图让我的代码简单明了以便理解,但这个解决方案太复杂了。最好的答案在第一部分 - 我做不到。
    • @RredCat 我发现这个解决方案简单易用。为什么说它太复杂?因为它使用 lambda?
    • @svick 是的。我个人喜欢 lambda,但我真正的方法有三个以上的参数。在这种情况下,方法的调用会看起来很奇怪、不清楚并且太长。 (类似于 MyMethod(param0, param1, param2, lambda))。
    • @RredCat 是否担心方法声明或何时调用?我个人更喜欢读取param2, number =&gt; "AAA{number}" 而不是param2, "AAA{0}" 的调用,尤其是当有多个格式参数时。它可以防止错误并且更具可读性。至于方法声明:您可以创建一个委托,它比 Func 参数更简洁,调用者仍然可以使用 lambda 表示法。 (例如 MyFormat format 而不是 Func&lt;long, int, string&gt; format
    • @enzi 我在这个方法中有其他参数,它看起来很长与 lambda。所以在我的案例中,我一直使用旧样式格式。但我喜欢这个 MyMethod(number => $"AAA{number:00}");方法也是。
    【解决方案2】:

    有几种方法可以做到这一点。

    第一个是添加另一个方法重载,该方法采用FormattableString(字符串轮询的一种变体使用的新类型)并调用原始方法:

    public void MyMethod(FormattableString fs)
    {
        MyMethod(fs.Format);
    }
    

    如果需要,您还可以访问参数。

    如果你只需要格式,只需创建一个扩展方法来提取它:

    public static string AsFormat(FormattableString fs)
    {
        return fs.Format;
    }
    

    【讨论】:

    • 我认为这行不通,因为“i 是在方法内部创建的”。
    • 我发现整个问题有点奇怪。我只是展示了一种从插值字符串中获取格式字符串的方法。
    • @svick 注意这是这里的解决方案,但您需要一直使用FormattableString(它会捕获完成格式化所需的参数)。
    • @Richard,它捕获了值。他们是如何到达那里的(参数、方法变量、类型字段等)丢失了。
    • 我不知道这是否回答了原始问题,但这是延迟字符串插值的好方法。非常适合用于条件日志等。
    【解决方案3】:

    自从有人问到这个问题几年后,我在搜索我脑海中已有的答案时通过 Google 发现了这个问题,但无法理解实现/语法。

    我的解决方案是对@Kobi 提供的进一步...

    public class Person
        {
            public int Id {get; set;}
            public DateTime DoB {get;set;}
            public String Name {get;set;}
        }
    
    public class MyResolver
    {
        public Func<Person, string> Resolve {get;set;}
        public string ResolveToString<T>(T r) where T : Person
        {
            return this.Resolve(r);
        }
    }
    
    // code to use here...
    var employee = new Person();
    employee.Id = 1234;
    employee.Name = "John";
    employee.DoB = new DateTime(1977,1,1);
    
    var resolver = new MyResolver();
    resolver.Resolve = x => $"This person is called {x.Name}, DoB is {x.DoB.ToString()} and their Id is {x.Id}";
    
    Console.WriteLine(resolver.ResolveToString(employee));
    

    我还没有测试上面的语法错误,但希望你明白了,你现在可以定义“如何”你希望字符串看起来,但根据你的值在运行时留下空白人物对象。

    干杯,

    韦恩

    【讨论】:

      【解决方案4】:

      这是不可能的。但是另一种方法是

      public static string MyMethod(string format, params object[] args)
      {
        if (format == null || args == null)
          throw new ArgumentNullException(format == null ? "format" : "args");
        return string.Format((IFormatProvider) null, format, args);
      }
      

      编辑:

      MyMethod("The number is {0}", 12);
      

      EDIT2:

      public static string MyMethod(string format)
      {
          var i = 12;
          var result = string.Format(null, format, i);
          return result;
      }
      MyMethod("{0:000}");
      

      【讨论】:

      • 这确实有效,但如果我正确理解了这个问题,12 来自MyMethod,而不是来自调用函数。另外,直接使用String.Format 有什么好处?
      • 您可以在该方法中使用args作为i,而不是调用方的i,但需要删除args参数。
      猜你喜欢
      • 2014-06-04
      • 2012-06-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-03
      • 2018-12-14
      相关资源
      最近更新 更多