Skip to content

C# Char da Int usato come stringa - l'equivalente reale di VB Chr()

La guida o codice che vedrai in questo articolo è la soluzione più semplice e valida che abbiamo trovato ai tuoi dubbi o dilemmi.

Soluzione:

Con questa domanda si apre il vaso di Pandora. Chr() è una funzione obsoleta in VB.NET; qualsiasi codice moderno dovrebbe invece utilizzare ChrW(). La differenza sta nel modo in cui il valore del carattere deve essere interpretato: ChrW() presuppone che il codice del carattere sia Unicode (W = wide). Chr() riporta indietro l'orologio al secolo precedente, un'età della pietra senza Unicode in cui i caratteri erano o nell'insieme di caratteri ASCII (0..127) o in un carattere "esteso" (128..255). Dove i caratteri estesi appartengono a un gruppo di caratteri pagina di codice. Erano in uso comune molte, molte pagine di codice diverse. Un disastro molto significativo: i programmi non potevano interpretare correttamente il testo generato da un'altra macchina situata in un paese diverso. O anche nello stesso paese, il Giappone aveva più pagine di codice in uso comune, nessuna delle quali era dominante. Produzione di mojibake.

Suppongo che tu intenda ChrW(), a nessuno piace il mojibake. Nemmeno C#. L'uso di Char.ToString() va bene, l'alternativa è usare il costruttore di stringhe che prende un elemento char:

  string mystring = new string((char)7, 1);

O la forma più generale che si potrebbe preferire:

  public static string ChrW(int code) {
      return new string((char)code, 1);
  }

Non è l'unico modo per farlo, anche l'uso dei letterali è possibile e probabilmente è quello che si preferisce rispetto a un metodo di aiuto. E la ragione fondamentale per cui C# non ha bisogno di una funzione di aiuto come Chr(). Il codice di controllo ASCII 7 è il carattere della campana, che fa suonare il campanello quando lo scrivete sulla console; potete usare un escape per questo:

  string mystring = "a";

Non proprio memorabile, proviene da Unix. Altri sono "b" per il backspace, "t" per il tab, "r" per il ritorno a capo e "n" per il line feed. Un trucco classico per cancellare l'ultimo carattere digitato in una finestra di console è il seguente Console.Write("b b");. Il carattere Environment.NewLine è da notare. Che è il massimo che si possa fare con i caratteri di controllo.

Infine, ma non meno importante, gli specificatori U e u consentono di codificare qualsiasi carattere:

  string mystring = "u0007";

Non è evidente dall'esempio, ma il valore u deve essere esadecimale. U è necessario quando si utilizzano i punti di codifica dei piani di bit superiori di Unicode.

Se si deve assolutamente usare il metodo Chr per motivi di legacy o altro, la cosa migliore è usarlo come metodo normale.

Se non volete importare VisualBasic o volete vedere come funziona, Reflector fornisce un bel pezzo di codice:

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

Per un carattere ASCII, chiama semplicemente Convert.ToCharche è equivalente a (char)CharCode. La prima cosa interessante è la chiamata a Utils.GetLocaleCodePage:

internal static int GetLocaleCodePage()
{
    return Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage;
}

Anche se ci si potrebbe aspettare che sia uguale a Encoding.Defaultcrea una codifica associata alla cultura del thread corrente, non al sistema. Il resto è solo un riempimento del codice in un array e l'uso della codifica per decodificarlo.

Questo metodo ha un'avvertenza importante, come sempre quando si ha a che fare con la codifica: dipende fortemente dal locale corrente e la modifica della cultura del thread corrente interrompe tutte le conversioni per i codici al di fuori dell'ASCII. Tuttavia, se è quello che si vuole fare, ecco un equivalente approssimativo e breve:

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

Mancano alcuni controlli del metodo originale, in particolare il controllo del singolo byte e dell'intervallo.

Esiste poi un metodo molto più semplice e migliore in VB.NET: ChrW per Unicode:

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

Anche in questo caso si ricorre a ToChar:

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

Come si può vedere, ChrW è uguale al vecchio metodo char conversione... tranne per i valori negativi! Anche se il codice del carattere deve essere contenuto in due byte, può provenire da un'origine breve sia firmata che non firmata, quindi il metodo si assicura che sia il numero giusto per entrambi i tipi di origine. Se si vuole tenere conto di questo aspetto, basta fare CharCode & 0xffff.

Quindi, come si può vedere, Chr è solo Encoding.GetChars dove la codifica è quella del thread corrente e ChrW è solo (char)CharCode, tranne che per il fatto che entrambe le funzioni gestiscono anche i valori negativi. Non ci sono altre differenze.


Per quanto riguarda la parte originale della domanda, non è possibile convertire da char a string perché... non c'è alcuna conversione possibile. Non si ereditano l'un l'altro, quindi non si possono lanciare, né hanno operatori di conversione definiti dall'utente e string non è un tipo di valore primitivo, quindi non c'è nemmeno una conversione integrata. VB.NET potrebbe permettere di fare questo, ma tutto sommato permette molte cose peggiori grazie alle sue vecchie versioni.

TL;DR È (char) è equivalente a Chr? Solo per il codice dei caratteri ASCII (da 0 a 127), altrimenti no. E Chr smette di funzionare se la codifica corrente e quella del codice differiscono, il che è importante se si usano caratteri non ASCII.

Solo per semplificare la sintassi. Quanto segue AChar gestisce le conversioni.

string A = (AChar)65;
Console.WriteLine(A); // output is "A"

La classe seguente rappresenta un carattere e definisce le conversioni dalla pagina di codice ASCII:

struct AChar
{
    public static implicit operator AChar(char value) => new AChar { Value = value };

    public static explicit operator AChar(string value)
    {
        if (string.IsNullOrEmpty(value))
            return 'x0000';

        if (value.Length > 1)
            throw new InvalidCastException("String contains more than 1 character.");

        return value[0];
    }

    public static explicit operator AChar(long value)
    {
        if(value < 0 || value > 0xFF)
            throw new InvalidCastException("Char code is out of ASCII range.");

        return (AChar)Encoding.ASCII.GetString(new[] { (byte)value });
    }

    public static implicit operator AChar(byte value) => (AChar)(long)value;
    public static explicit operator AChar(int value) => (AChar)(long)value;

    public static implicit operator char(AChar aChar) => aChar.Value;
    public static implicit operator string(AChar aChar) => aChar.Value.ToString();

    public static bool operator==(AChar left, AChar right) =>
        left.Value == right.Value;

    public static bool operator!=(AChar left, AChar right) =>
        left.Value != right.Value;

    public static bool operator >(AChar left, AChar right) =>
        left.Value > right.Value;

    public static bool operator >=(AChar left, AChar right) =>
        left.Value >= right.Value;

    public static bool operator <(AChar left, AChar right) =>
        left.Value < right.Value;

    public static bool operator <=(AChar left, AChar right) =>
        left.Value <= right.Value;

    public override string ToString() => this;

    public override int GetHashCode() =>    
        Value.GetHashCode();

    public override bool Equals(object obj) =>
        obj is AChar && ((AChar)obj).Value == Value;

    char Value { get; set; }
}

Convertire prima il codice dei caratteri in AChar, è compatibile con char e string di C#.

Sezione recensioni e valutazioni

Se ti piace l'idea, puoi lasciare un tutorial su cosa ne pensi di questo tutorial.



Utilizzate il nostro motore di ricerca

Ricerca
Generic filters

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.