web-dev-qa-db-fra.com

Lancer sbyte [] pour bool [] et un caractère [] pour abréger []

Y at-il de toute façon à explicitement cast/coercer 

  • sbyte[] ou byte[] à un bool[] 
  • char[] à un short[]/ushort[]

Dans CIL, vous voyez régulièrement quelque chose comme 

stelem Type sbyte (ldloc pArray) ldc_i4 1 ldc_i4 0 

qui fait pArray[1] = truepArray est un tableau unidimensionnel de type bool[]. Je veux reproduire cela en c # en faisant 

(sbyte[])pArray[1] = 1;

Malheureusement, cela n’est pas autorisé par le compilateur C #. 

12
Nick

Vous pouvez utiliser les nouveaux types Span<T> et MemoryMarshal pour le faire.

Notez que cela n’est disponible que dans les versions récentes de C # et que vous devez utiliser un package NuGet pour fournir la bibliothèque pour le moment, mais cela va changer.

Ainsi, par exemple, pour "convertir" un tableau de caractères en un tableau court, vous pouvez écrire le code suivant:

var         charArray  = new char[100];
Span<short> shortArray = MemoryMarshal.Cast<char, short>(charArray);

charArray[0] = 'X';
Console.WriteLine(charArray[0]); // Prints 'X'
++shortArray[0];
Console.WriteLine(charArray[0]); // Prints 'Y'

Cette approche est documentée et ne crée aucune copie des données. Elle est également extrêmement performante (de par sa conception).

Notez que cela fonctionne aussi avec les structs:

struct Test
{
    public int X;
    public int Y;

    public override string ToString()
    {
        return $"X={X}, Y={Y}";
    }
}

...

var testArray = new Test[100];
Span<long> longArray = MemoryMarshal.Cast<Test, long>(testArray);

testArray[0].X = 1;
testArray[0].Y = 2;

Console.WriteLine(testArray[0]); // Prints X=1, Y=2

longArray[0] = 0x0000000300000004;

Console.WriteLine(testArray[0]); // Prints X=4, Y=3

Notez également que cela vous permet de faire des choses suspectes, comme ceci:

struct Test1
{
    public int X;
    public int Y;

    public override string ToString()
    {
        return $"X={X}, Y={Y}";
    }
}

struct Test2
{
    public int X;
    public int Y;
    public int Z;

    public override string ToString()
    {
        return $"X={X}, Y={Y}, Z={Z}";
    }
}

...

var         test1 = new Test1[100];
Span<Test2> test2 = MemoryMarshal.Cast<Test1, Test2>(test1);

test1[1].X = 1;
test1[1].Y = 2;

Console.WriteLine(test1[1]); // Prints X=1, Y=2

test2[0].Z = 10; // Actually sets test1[1].X.

Console.WriteLine(test1[1]); // Prints X=10, Y=2
9
Matthew Watson

Ceci n'est qu'une réponse partielle.

Pirater:

Le compilateur C # et le run-time ne sont pas entièrement d'accord sur les types de tableaux convertibles l'un pour l'autre (comme vous l'indiquez dans votre question). Ainsi, vous pouvez éviter de demander au compilateur et de différer la conversion en exécution en passant par System.Array (ou System.Object ou System.Collections.IEnumerable etc.).

Un exemple:

using System;

static class P
{
  static void Main()
  {
    var a = new sbyte[] { -7, -3, 8, 11, };
    var hack = (byte[])(Array)a;
    Console.WriteLine(string.Join("\r\n", hack));
  }
}

Essayez-le en ligne (tio.run)

Sortie:

249 
 253 
 8 
 11

Si vous deviez éviter le (Array) intermédiaire dans le code ci-dessus, le compilateur C # vous dirait que la conversion est impossible.

1

Vous pouvez utiliser une méthode d'extension, comme ceci: 

namespace ExtensionMethods
{
    public static class ByteExt
    {
        public static bool ToBool(this byte b) => b != 0;
        public static bool[] ToBoolArray(this byte[] bytes)
        {
            bool[] returnValues = new bool[bytes.Length];

            for (int i = 0; i < bytes.Length; i++)
                returnValues[i] = bytes[i].ToBool();

            return returnValues;
        }

        // Do same for sbyte
    }
    public static class CharExt
    {
        public static short[] ToBoolArray(this char[] chars)
        {
            short[] returnValues = new bool[chars.Length];

            for (int i = 0; i < chars.Length; i++)
                returnValues[0] = (short)chars[0];

            return returnValues;
        }
    }
}

Ensuite, utilisez-le comme ceci: 

byte[] myBytes = new[] {1, 2, 5};
bool[] myBools = myBytes.ToBoolArray();

En C # 8, il y aura probablement ce qu'on appelle "Extension Everything", où vous pourrez définir vos propres transtensions d'extension, à la fois explicites et implicites. 

La syntaxe ressemblera à ceci:

public extension class ByteExt extends Byte[]
{
    public static explicit operator bool[](byte[] bytes)
    {
         // Same implementation as before
    }
}

Et peut l'utiliser comme ça: 

byte[] myBytes = new[] {1, 2, 5};
bool[] myBools = (bool[])myBytes;
0
AustinWBryan