将sbyte []转换为bool []并将char []转换为short []

时间:2018-05-23 09:17:04

标签: c# casting

无论如何都要明确施放/强制

  • sbyte[]byte[]bool[]
  • char[]short[] / ushort[]

在CIL中,您经常会看到诸如

之类的内容
stelem Type sbyte (ldloc pArray) ldc_i4 1 ldc_i4 0 

正在执行pArray[1] = true,其中pArray是类型为bool[]的一维数组。我想通过执行

在c#中复制它
(sbyte[])pArray[1] = 1;

不幸的是,C#编译器不允许这样做。

5 个答案:

答案 0 :(得分:17)

未记录的技巧,自担风险:

(例如here和许多其他地方显示)

[StructLayout(LayoutKind.Explicit)]
public struct ConvSByteBool
{
    [FieldOffset(0)]
    public sbyte[] In;
    [FieldOffset(0)]
    public bool[] Out;
}

然后:

var bytes = new sbyte[] { -2, -1, 0, 1, 2 };
var conv = new ConvSByteBool { In = bytes }.Out;
bool b1 = conv[0]; // true
bool b2 = conv[1]; // true
bool b3 = conv[2]; // false
bool b4 = conv[3]; // true
bool b5 = conv[4]; // true

请注意,这个技巧与泛型有点不兼容。没有Conv<T, U>

当源和目标中的元素大小相同(sizeof(sbyte) == sizeof(bool))时,该技巧最有效。否则会有一些限制(在上面的链接问题中描述)。

答案 1 :(得分:9)

您可以使用the new Span<T> and MemoryMarshal types执行此操作。

请注意,这仅适用于最新版本的C#,您现在必须使用NuGet包来提供库,但这会发生变化。

例如,对于&#34;演员&#34;一个char数组到一个短数组,你可以编写如下代码:

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'

此方法已记录在案,并且不会复制任何数据 - 并且它的性能也非常高(按设计)。

请注意,这也适用于结构:

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

另请注意,这可以让您做一些可疑的事情,例如:

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

答案 2 :(得分:1)

这只是部分答案。

哈克:

C#编译器和运行时完全不同意哪些数组类型可以相互转换(正如您在问题中暗示的那样)。因此,您可以通过System.Array(或System.ObjectSystem.Collections.IEnumerable等)来避免询问编译器并将强制转换推迟到运行时。

一个例子:

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

Try it online (tio.run)

输出:

249
253
8
11

如果你要避免上面代码中的中间(Array),C#编译器会告诉你演员阵容是不可能的。

答案 3 :(得分:0)

您可以使用扩展方法,如下所示:

    $.ajax({
    type: 'post',
    url: "https://gateway.watsonplatform.net/assistant/api/v1/workspaces/XXX...XXX/message?version=20XX-XX-XX",        
    data: "{ \"input\": {\"text\": \"Hello\"}} ",          
    headers : {'Content-Type' : 'application/json' },
    u : { 'uname' : 'pwd' },
    success:function(response)
    {
        console.log("Success!!");
    },

    error : function(xhr, status, error)
    {
        console.log("Status of error message" + status + "Error is" + error);
    }   

    });

然后就这样使用它:

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

在C#8中,可能会出现所谓的“扩展所有内容”,您可以在其中定义自己的扩展转换,包括显式和隐式。

语法将是这样的:

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

可以像这样使用它:

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

答案 4 :(得分:-1)

使用Array.ConvertAll如下:

// Input
sbyte[] sbyteArray = { 0, 1, 2, 0 };
byte[] byteArray = { 0, 1, 2, 0 };
// Result
bool[] boolArray1 = Array.ConvertAll(sbyteArray, (item) => Convert.ToBoolean(item));
bool[] boolArray2 = Array.ConvertAll(byteArray, (item) => Convert.ToBoolean(item));

// Input
char[] charArray = { 'A', 'B', 'C' };
// Result
short[] shortArray = Array.ConvertAll(charArray, (item) => Convert.ToInt16(item));
ushort[] ushortArray = Array.ConvertAll(charArray, (item) => Convert.ToUInt16(item));