简体   繁体   English

在C#中将Int32转换为T并将T []转换为Int32 []

[英]Converting `Int32` to `T` and `T []` to `Int32 []` in C#

I was attempting to write a simple function that would use the RandomNumberGenerator class to return an array of Int16 , Int32 or Int64 based on a generic argument. 我试图编写一个简单的函数,该函数将使用RandomNumberGenerator类基于通用参数返回Int16Int32Int64数组。

However, no matter how I try to structure the code, I cannot seem to get past the illegal conversion from T [] to short/int/long [] , nor the conversion from IntXX to T . 但是,无论我如何尝试构建代码,我似乎都无法摆脱从T []short/int/long []的非法转换,也无法IntXXIntXXT的转换。 Please see the two comments in the code below. 请在下面的代码中看到两个注释。

It seems I am missing a basic construct that would allow a way around this. 似乎我缺少一个基本的结构,它可以解决这个问题。 Any thoughts? 有什么想法吗?

public static void GenerateRandom<T> (T [] data, bool nonZeroOnly = false)
    where T: struct, System.IComparable, System.IFormattable, System.IConvertible
{
    int size = 0;
    byte [] bytes = null;

    if ((typeof(T) != typeof(byte)) && (typeof(T) != typeof(short)) && (typeof(T) != typeof(int)) && (typeof(T) != typeof(long)))
    {
        throw (new System.ArgumentException("This method only accepts types [Byte], [Int16], [Int32], or [Int64].", "<T>"));
    }

    if (typeof(T) == typeof(byte))
    {
        using (System.Security.Cryptography.RandomNumberGenerator generator = System.Security.Cryptography.RandomNumberGenerator.Create())
        {
            // Invalid cast (implicit or explicit) from T [] to byte [].
            if (nonZeroOnly) { generator.GetNonZeroBytes(data); }
            else { generator.GetBytes(data); }
        }
    }
    else
    {
        size = System.Runtime.InteropServices.Marshal.SizeOf(typeof(T));    
        bytes = new byte [data.Length * size];

        using (System.Security.Cryptography.RandomNumberGenerator generator = System.Security.Cryptography.RandomNumberGenerator.Create())
        {
            if (nonZeroOnly) { generator.GetNonZeroBytes((byte []) System.Convert.ChangeType(data, typeof(byte []))); }
        else { generator.GetBytes((byte []) System.Convert.ChangeType(data, typeof(byte []))); }
        }

        using (System.IO.MemoryStream stream = new System.IO.MemoryStream(bytes))
        {
            using (System.IO.BinaryReader reader = new System.IO.BinaryReader(stream))
            {
                // Invalid cast (implicit or explicit) from short/int/long to T.
                if (typeof(T) == typeof(short)) { for (int i=0; i<bytes.Length; i+=size) { data[i] = reader.ReadInt16(); } }
                else if (typeof(T) == typeof(int)) { for (int i=0; i<bytes.Length; i+=size) { data[i] = reader.ReadInt32(); } }
                else if (typeof(T) == typeof(long)) { for (int i=0; i<bytes.Length; i+=size) { data[i] = reader.ReadInt64(); } }
            }
        }
    }
}

On a side note, is there a more efficient way of converting a byte [] to a IntXX [] without using a stream and binary reader? 附带说明一下,是否有一种更有效的方法,可以在不使用流和二进制读取器的情况下将byte []转换为IntXX []

You can do this, to get from int to T : 您可以这样做,从intT

void Foo<T>(T[] data)
{
    ...
    int v = r.Next(255);  // limit to byte.max for simplicity
    data[i] = (T) Convert.ChangeType(v, typeof(T));
}

I think you are trying to be clever here and in the process making things far too complex. 我认为您在这里和过程中要变得聪明,使事情变得过于复杂。 Just write threee separate methods: 只需编写三个单独的方法:

Int16[] GenerateRandomShorts()
Int32[] GenerateRandomInts()
Int64[] GenerateRandomLongs()

There is absolutely no reason to use generics here, and the problems you are facing are the result of swimming against the current. 这里绝对没有理由使用泛型,而您面临的问题是逆流而行的结果。

Simply use non-generic overloads and let the compiler pick the one to use based on the type of the first argument: 只需使用非泛型重载,然后让编译器根据第一个参数的类型选择要使用的重载:

public static void GenerateRandom(byte[] data, bool nonZeroOnly = false)
{
    using (var generator = RandomNumberGenerator.Create())
    {
        if (nonZeroOnly) { generator.GetNonZeroBytes(data); }
        else { generator.GetBytes(data); }
    }
}

public static void GenerateRandom(short[] data, bool nonZeroOnly = false)
{
    var size = sizeof(short);
    var bytes = new byte[data.Length * size];

    GenerateRandom(bytes, nonZeroOnly);

    for (var i = 0; i < data.Length; ++i) {
        data[i] = BitConverter.ToInt16(bytes, i * size);
    }
}

Two more overloads like the last one would take care of int and long . 像最后一个这样的另外两个重载将处理intlong

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM