C# 仅将任何类型的数组的一个方法设置为IntPtr

C# 仅将任何类型的数组的一个方法设置为IntPtr,c#,C#,具有将double[]d转换为IntPtr的方法,如: public static IntPtr DoubleArrayToIntPtr(double[] d) { IntPtr p = Marshal.AllocCoTaskMem(sizeof(double) * d.Length); Marshal.Copy(d, 0, p, d.Length); return p; } 制作int[],float[]等的最佳方法是什么。我正在考虑为每种类型制作一种方法,比如添加int[

具有将
double[]d
转换为
IntPtr
的方法,如:

public static IntPtr DoubleArrayToIntPtr(double[] d)
{
   IntPtr p = Marshal.AllocCoTaskMem(sizeof(double) * d.Length);
   Marshal.Copy(d, 0, p, d.Length);
   return p;
}
制作
int[]
float[]
等的最佳方法是什么。我正在考虑为每种类型制作一种方法,比如添加int[]:

public static IntPtr IntArrayToIntPtr(int[] d)
{
   IntPtr p = Marshal.AllocCoTaskMem(sizeof(int) * d.Length);
   Marshal.Copy(d, 0, p, d.Length);
   return p;
}
1.这种方法是否可以推广,如果可以,如何推广


2.是否可以只在一行代码中获取指针(因为封送是无效的方法)?

要回答您的第一个问题,是的,可以概括为:

public static IntPtr ArrayToIntPtr<T>(T[] d) where T : struct
{
     var arrayType = typeof(T);
     IntPtr p = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(T)) * d.Length);
     if (arrayType == typeof(int))
     {
          Marshal.Copy((int[])(object)d, 0, p, d.Length);
     }
     //else if ....other types you want to handle
     return p;
}
公共静态IntPtr数组IntPtr(T[]d),其中T:struct
{
var arrayType=typeof(T);
IntPtr p=Marshal.alloctaskmem(Marshal.SizeOf(typeof(T))*d.Length;
if(arrayType==typeof(int))
{
封送处理副本((int[])(object)d,0,p,d.Length);
}
//否则,如果…您要处理的其他类型
返回p;
}
我添加了struct的类型约束,它将您限制为值类型(short、double、int、struct)。显然,您需要注意传入的内容(比如传入结构)

为了回答你的第二个问题,不,我不认为你可以把它缩减到一行,即使你可以,你可能也不想为了可读性而这样做

编辑

我已经在评论中修复了由SiLo确定的问题,但是这段代码现在非常难看,我不能说我会推荐这种方法。很明显,它需要进行大量的类型检查和装箱以获得正确的类型。事实上,我个人推荐遵循Silo's而不是我的,尽管我至少已经证明了你可以用一种准泛型的方式来实现这一点,尽管首先肯定会打破泛型的精神。

最好的方法是为每种类型创建一个扩展类,为你做到这一点。由于
Marshal.Copy()
不支持泛型类型,因此不能将其设置为泛型。因此,您必须对每种类型的
byte
char
int
long
float
double
,等等复制您的方法。不过,您可以使用通用的助手方法来确定您的大小为
marshal

以下内容可能对您有用:

public static class MarshalExtender
{
    public static IntPtr CopyToCoTaskMem(this byte[] array)
    {
        var ptr = AllocArrayCoTaskMem(array);

        Marshal.Copy(array, 0, ptr, array.Length);
        return ptr;
    }

    // Copy the above method and replace types as needed (int, double, etc).

    // Helper method for allocating bytes with generic arrays.
    static IntPtr AllocArrayCoTaskMem<T>(T[] array)
    {
        var type = typeof(T);
        var size = Marshal.SizeOf(type) * array.Length;
        return Marshal.AllocCoTaskMem(size);
    }
}
注意:完成后一定要调用
Marshal.FreeCoTaskMem()
!我建议您的扩展方法返回一个
IDisposable
对象,这样您就可以使用
块将其包装在

例如:

public sealed class CoTaskMemoryHandle : IDisposable
{
    bool isDisposed;
    readonly IntPtr handle;

    public IntPtr Handle { get { return handle; } }

    public CoTaskMemoryHandle(IntPtr handle)
    {
        this.handle = handle;
    }

    public void Dispose()
    {
        OnDispose(true);
        GC.SuppressFinalize(this);
    }

    void OnDispose(bool isDisposing)
    {
        if (isDisposed) return;

        if (isDisposing)
        {
            if (handle != IntPtr.Zero)
                Marshal.FreeCoTaskMem(handle);
        }

        isDisposed = true;
    }
}
然后修改扩展类方法:

public static CoTaskMemoryHandle CopyToCoTaskMem(this byte[] array)
{
    var ptr = AllocArrayCoTaskMem(array);

    Marshal.Copy(array, 0, ptr, array.Length);
    return new CoTaskMemoryHandle(ptr);
}
这样您就可以安全地封装
Alloc
/
Free
平衡:

using(myArray.CopyToCoTaskMem())
{
   // Do something here..
}

你需要intptr做什么?这决定了它将如何被封送。你真的想要一个副本,还是一个文本转换模板工具包。简称T4。这有几个问题。首先,对于需要在不安全的环境中使用的
sizeof
,您将收到一条警告,这是不推荐的<应改用code>Marshal.SizeOf()
。即使如此,
Marshal.Copy
也不支持泛型参数,这是行不通的。@这是我用SO而不是用实际的C#editorNo编写代码的结果。我有时倾向于这样做,所以我理解。我对此很好奇,所以我启动了VS来看看。不幸的是,事情并非如此简单(似乎需要单独的重载,但它们可能是相当小的方法。我建议使用继承而不是
IDisposable
。是的!我刚刚想到了这个!
using(myArray.CopyToCoTaskMem())
{
   // Do something here..
}