来自Int的C#Char用作String - VB Chr()的真正等价物

ib1*_*b11 10 c# string vba casting char

我试图找到我的问题的明确答案,它不是网站上任何其他问题的重复.在SO和其他几个网站上,我已经阅读了很多关于此的帖子和相关问题.例如,这是一个关键答案(许多其他人被标记为dulpicates并重定向到这个):在C#中VB的Asc()和Chr()函数的等价物是什么?

我正在将VBA宏转换为C#.在VBA中chr(7)可以简单地连接到一个string好像chr()会产生一个string.为什么不能在C#中完成?

不幸的是,答案并不清楚,很多时候他们说这是正确的用法:

string mystring=(char)7;
Run Code Online (Sandbox Code Playgroud)

然而它给了我一个编译器错误,因为它不作为一个字符串进行评估.

我不得不用它来使它工作:

string mystring=((char)7).ToString();
Run Code Online (Sandbox Code Playgroud)

这相当于VB Chr()函数,实际上VB中的Chr()计算为字符串.

我的问题是这样的:我总是需要转换charstring明确或有一些情况下,其转换在含蓄?

更新:

Per @ Dirk的答案,这也有效:

string mystring = "" + (char)7;
Run Code Online (Sandbox Code Playgroud)

这并没有减少我的神秘感.如果连接起作用,为什么没有隐式转换?

我希望得到VB Chr()与C#中的等价物之间差异的完整解释.我很感激任何我可以阅读的参考文献,甚至是例子.提前致谢.

Han*_*ant 23

你正在用这个问题打开潘多拉盒子.Chr()是VB.NET中的遗留函数,任何现代代码都应该使用ChrW().不同之处在于应该解释字符值的方式,ChrW()假定字符代码是Unicode(W =宽).Chr()将时钟回滚到上个世纪,这是一个没有Unicode的石器时代,其中字符是ASCII字符集(0..127)或"扩展"字符(128..255).扩展字符属于代码页的位置.许多不同的代码页都是常用的.这是一个非常重大的灾难,程序无法正确解释由位于不同国家/地区的另一台计算机生成的文本.甚至在同一个国家,日本也有多个共同使用的代码页,但没有一个占主导地位.制作mojibake.

我猜你的意思是ChrW(),没有人喜欢mojibake.也不是C#.使用Char.ToString()很好,另一种方法是使用带有以下内容的字符串构造函数char:

  string mystring = new string((char)7, 1);
Run Code Online (Sandbox Code Playgroud)

或者您可能更喜欢的更一般的形式:

  public static string ChrW(int code) {
      return new string((char)code, 1);
  }
Run Code Online (Sandbox Code Playgroud)

不是唯一的方法,使用文字是可能的,并且可能是你喜欢的辅助方法.而且C#不需要像Chr()这样的辅助函数的基本原因.ASCII控制代码7是铃声字符,当你把它写到控制台时它会让你烦恼,你可以使用转义:

  string mystring = "\a";
Run Code Online (Sandbox Code Playgroud)

不完全令人难忘,这来自Unix.其他的是"\ b"表示退格,"\ t"表示选项卡,"\ r"表示回车符,"\n"表示换行符.擦除控制台窗口中最后一个键入字符的经典技巧是Console.Write("\b \b");.该Environment.NewLine物业应予以注意.至于你应该用控制字符来推动它.

最后但并非最不重要的是\ U和\ u说明符可以让你编码任何字符:

  string mystring = "\u0007";
Run Code Online (Sandbox Code Playgroud)

从示例中不明显但是\ u值必须是十六进制的.当您使用来自上部Unicode位平面的代码点时,需要\ U.

  • 谢谢.潘多拉的盒子很少有简单的内容. (2认同)
  • 不,"不是C#"也是我想要的.SO用户对他们的首选语言充满热情,他们也应该这样,他们强烈不喜欢任何类似"你不能那样做"或"更难"的东西.它们都是优秀的语言,只是不同. (2认同)

Ill*_*ack 6

如果绝对必须使用Chr方法,那么最好的办法是将它作为常规方法使用.

如果您不想导入VisualBasic,或想要查看它是如何工作的,Reflector会提供一段很好的代码:

public static char Chr(int CharCode)
{
    char ch;
    if ((CharCode < -32768) || (CharCode > 0xffff))
    {
        throw new ArgumentException(Utils.GetResourceString("Argument_RangeTwoBytes1", new string[] { "CharCode" }));
    }
    if ((CharCode >= 0) && (CharCode <= 0x7f))
    {
        return Convert.ToChar(CharCode);
    }
    try
    {
        int num;
        Encoding encoding = Encoding.GetEncoding(Utils.GetLocaleCodePage());
        if (encoding.IsSingleByte && ((CharCode < 0) || (CharCode > 0xff)))
        {
            throw ExceptionUtils.VbMakeException(5);
        }
        char[] chars = new char[2];
        byte[] bytes = new byte[2];
        Decoder decoder = encoding.GetDecoder();
        if ((CharCode >= 0) && (CharCode <= 0xff))
        {
            bytes[0] = (byte) (CharCode & 0xff);
            num = decoder.GetChars(bytes, 0, 1, chars, 0);
        }
        else
        {
            bytes[0] = (byte) ((CharCode & 0xff00) >> 8);
            bytes[1] = (byte) (CharCode & 0xff);
            num = decoder.GetChars(bytes, 0, 2, chars, 0);
        }
        ch = chars[0];
    }
    catch (Exception exception)
    {
        throw exception;
    }
    return ch;
}
Run Code Online (Sandbox Code Playgroud)

对于ASCII字符,它只是调用Convert.ToChar,相当于(char)CharCode.第一个有趣的事情是呼吁Utils.GetLocaleCodePage:

internal static int GetLocaleCodePage()
{
    return Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage;
}
Run Code Online (Sandbox Code Playgroud)

虽然人们可能期望它与之相同Encoding.Default,但它会创建与当前线程的文化相关联的编码,而不是系统.其余的只是将代码填充到一个数组中并使用编码对其进行解码.

这种方法有一个主要的警告,就像处理编码时一样 - 它在很大程度上取决于当前的语言环境,而改变当前线程的文化会破坏ASCII以外代码的所有转换.但是,如果就是你想要做的,这里有一个粗略而简短的等价物:

public static char Chr(int code)
{
    var encoding = Encoding.GetEncoding(Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage);
    return encoding.GetChars(BitConverter.GetBytes((ushort)code))[0];
}
Run Code Online (Sandbox Code Playgroud)

这缺少对原始方法的一些检查,尤其是单字节和范围检查.

然后在VB.NET中有一个更简单,更好的方法 - 用于Unicode的ChrW:

public static char ChrW(int CharCode)
{
    if ((CharCode < -32768) || (CharCode > 0xffff))
    {
        throw new ArgumentException(Utils.GetResourceString("Argument_RangeTwoBytes1", new string[] { "CharCode" }));
    }
    return Convert.ToChar((int) (CharCode & 0xffff));
}
Run Code Online (Sandbox Code Playgroud)

这又回到了ToChar:

public static char ToChar(int value)
{
    if ((value < 0) || (value > 0xffff))
    {
        throw new OverflowException(Environment.GetResourceString("Overflow_Char"));
    }
    return (char) value;
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,ChrW与普通旧char转换相同...... 除了负值!你知道,尽管字符代码必须符合两个字节,但它可能来自有符号或无符号短,因此该方法确保它对于两种类型的原点都是正确的数字.如果你想考虑到这一点,那就做吧CharCode & 0xffff.

因此,大家可以看到,Chr仅仅是Encoding.GetChars其中编码是当前线程的一个,并且ChrW仅仅是(char)CharCode,除了这两个功能也处理负值.没有其他区别.


至于你问题的原始部分,你无法转换charstring因为......没有可能的转换.它们不会相互继承,因此您无法转换它们,它们也没有任何用户定义的转换运算符,string也不是原始值类型,因此也没有内置转换.VB.NET可能允许你这样做,但总而言之,由于它的古老版本,它允许许多更糟糕的事情.

TL; DR (char)相当于Chr?仅适用于ASCII字符代码(0到127),否则为no.而Chr停止工作,如果当前的编码和代码编码不同,如果使用非ASCII字符,这无关紧要.