首页 > 解决方案 > 如何获取对数组第一个元素的引用

问题描述

我有一个转换器例程,可以将数组类型转换/转换为另一个。最初的方法是这样的:

static void Convert<TTo>(Array source, TTo[] target);

但是以后有需要和Span一起去,所以新的方法应该是这样的

static void Convert<TTo>(Array source, in Span<TTo> target)

目前我在内部例程中调用转换

public double GetSumOfAbsoluteDifferences(Array imageData1, Add imageData2)
{
  // Convert to float
  float[] id1 = new float[imageData1.Length];
  float[] id2 = new float[imageData2.Length];

  DataConversion.Convert<float>(imageData1, id1);
  DataConversion.Convert<float>(imageData2, id2);

  double sum=0;
  for (int i=0; i<imageData1.Length; i++)
  {
    sum += Math.Abs(id1[i] - id2[i]);
  }

  return sum;
}

旧方法能够将数组的任何维度转换为一维数组,这是可以的。最初我不得不做很多不安全的代码来使方法尽可能通用,至少对于结构或非托管类型。由于我没有输入版本,Array因此我需要执行 GCHandle.Alloc 并在强制转换时固定数组。我当前的实现如下所示(为简洁起见,仅显示了一个转换器):

public unsafe static class DataConversion
{
    public delegate void Converter(void* source, void* target, int n);
    
    readonly static Dictionary<Type, Dictionary<Type, Converter>> Converters = new Dictionary<Type, Dictionary<Type, Converter>>();
    
    static DataConversion()
    {
        Converters.Add(typeof(int), new Dictionary<Type, Converter>()
            {
                [typeof(float)] = Convert_Int_Float
            }
        );
    }
    
    private unsafe static void Convert<TTo>(Array source, in Span<TTo> target)
    {
        GCHandle handle = GCHandle.Alloc(source, GCHandleType.Pinned);
    
        var sourceType = source.GetType().GetElementType();
    
        Converter converter = Converters[sourceType][typeof(TTo)];
        converter(handle.AddrOfPinnedObject().ToPointer(), Unsafe.AsPointer(ref target[0]), source.Length);
    
        handle.Free();
    }
    
    private static unsafe void Convert_Int_Float(void* source, void* target, int n)
    {
        var from = new ReadOnlySpan<int>(source, n);
        var to = new Span<float>(target, n);
    
        for (int i = 0; i < n; i++)
            to[i] = (float)from[i];
    }
}

我的问题是,是否可以在没有任何不安全代码的情况下做到这一点?我遇到的问题是我无法使转换器方法(此处Convert_Int_Float:)通用,因为那时它们不适合字典。我唯一的选择是将它放入最通用的版本是/是void *

所以我的问题是是否有更好的方法?

标签: c#

解决方案


推荐阅读