【问题标题】:Why is my `char` argument in an extension method interpreted as `int`? [duplicate]为什么我在扩展方法中的 `char` 参数被解释为 `int`? [复制]
【发布时间】:2021-05-15 11:53:26
【问题描述】:

我为string编写了一个带有非常简单扩展方法的.DLL库。

我的方法 - .Remove(char deletedChar),删除 string 中所有出现的 char。这会重载默认的 .Remove(int startIndex) 方法。但是,当我想使用它时,会调用.Remove(int startIndex),而不是我的方法,尽管我将char 作为参数。

我的意思是,给定这段代码:

string Test = "12-34-56-78-90-123-456-789-0123-4567-89012-34567-890123-456789-000000";
MessageBox.Show(Test.Remove('-'));

我的预期结果是:

1234567890123456789012345678901234567890123456789000000

但是,实际结果是:

12-34-56-78-90-123-456-789-0123-4567-89012-34

查看截图:

这意味着,我的char '-' 被解释为它的 ASCII 值 (45),这是删除字符串的起始索引。

为什么会这样?即使将char 转换为char(即(char)'-')也无法修复它。我知道我可以简单地重命名扩展方法,但我仍然不明白为什么会发生这种情况。有人可以解释这种现象或指出解释它的文档吗?

粘贴我的扩展方法以防有人想要使用它:

    /// <summary>
    /// Removes all occurences of specified char.
    /// </summary>
    /// <param name="str"></param>
    /// <param name="deletedChar">The char you want to remove.</param>
    /// <returns>string without the specified char.</returns>
    public static string Remove(this string str, char deletedChar)
    {
        for (int i = 0; i < str.Length; i++)
        {
            if (str[i] == deletedChar)
            {
                str = str.Remove(i, 1);
                i--;
            }
        }
        return str;
    }

【问题讨论】:

    标签: c# dll extension-methods


    【解决方案1】:

    如果找到扩展,则在扩展之前调用 C# 实例方法。

    来自documentation

    当编译器找不到具有匹配签名的实例方法时,如果存在,它将绑定到匹配的扩展方法。

    编写这个帮助类,我们可以看到好的方法被调用了:

    public static class StringHelper
    {
      public static string MyRemove(this string str, int index)
      {
        return "remove at index";
      }
      public static string MyRemove(this string str, char code)
      {
        return "remove all chars";
      }
    }
    

    测试

    Console.WriteLine("".MyRemove(1));
    Console.WriteLine("".MyRemove('a'));
    

    输出

    remove at index
    remove all chars
    

    因此解决方案是使用专用方法的名称:

    public static class StringHelper
    {
      public static string RemoveAll(this string str, char deletedChar)
      {
        for ( int i = 0; i < str.Length; i++ )
        {
          if ( str[i] == deletedChar )
          {
            str = str.Remove(i, 1);
            i--;
          }
        }
        return str;
      }
    }
    

    因此设计和使用更清晰,更干净,而且参数的类型告诉删除什么。

    但是这种方法没有优化,例如可以替换为:

    public static string RemoveAll(this string str, char code)
    {
      return str.Replace(code.ToString(), "");
    }
    

    或者这个更好:

    using System.Text;
    
    public static string RemoveAll(this string str, char code)
    {
      var builder = new StringBuilder();
      foreach ( char c in str )
        if ( c != code )
          builder.Append(c);
      return builder.ToString();
    }
    

    或者使用 Linq,但可能不如以前优化:

    using System.Linq;
    
    public static string RemoveAll(this string str, char code)
    {
      return new string(str.Where(c => c != code).ToArray());
    }
    

    【讨论】:

    • 感谢您的回答,但是这一行 return str.Replace(code.ToString(), ""); 会抛出 CS1011 Empty character literal。另外,我不太明白您的方法如何更优化,因为我的复杂度为 O(n)(与您的相同)。
    • 这里没有提出 CS1011。你能更具体地说明你在说什么吗?否则,StringBuilder 的使用可能是最本机优化的(从未进行过基准测试)。
    • 这是我的错误,使用.Replace(char oldChar, char newChar)方法重载时会抛出CS1011。我没有注意到您使用字符串代替。现在它不会抛出错误,谢谢 :) 至于优化,你和我的代码都具有线性复杂度(O(n),其中 n -> str.Length)。
    • @KifoPL 实际上,这种方法禁止使用空字符'''\0'
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-16
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    相关资源
    最近更新 更多