C#中的指针作为泛型

4

有人知道是否可以将原始类型作为通用参数吗。

请注意,在开始讨论我不应该使用指针之前。

这些图像是使用IPP分配的原始数据数组,大部分时间我会使用IPP,这部分是在需要或更喜欢以非IPP支持方式单独处理数据时将数据从非托管转换为托管数据的过程。

我需要以下字节、浮点、短组合的函数,而且我希望使用一些通用/模板风格的东西,而不是编写所有明确的组合。

private static unsafe List<PixelF> GetPixels<Timg,Tmask>(
  VMImage img, 
  int band, 
  VMImage imgMask, 
  int bandMask)

其中Timg和TMask可以是一个(byte、short或float)

现在,一个函数看起来像这样。

private static unsafe List<PixelF> GetPixels_FloatImg_ByteMask(
  VMImage img, 
  int band, 
  VMImage imgMask, 
  int bandMask)
{
  List<PixelF> pixValues = new List<PixelF>();
  int r, c;
  int imgSrcOffset = img.LineLength - img.Width;
  int imgMaskOffset = imgMask.LineLength - imgMask.Width;
  float* pf_imgSrc = (float*)img.GetRoiPointer(band);
  byte* pb_imgMask = (byte*)imgMask.GetRoiPointer(bandMask);
  for (r = 0; r < img.Height; r++) // Loop over rows
  {
    for (c = 0; c < img.Width; c++) // Loop over columns
    {
      if (*pb_imgMask > 0)
      {
        pixValues.Add(new PixelF(c, r, (float)*pf_imgSrc));
      }
      ++pf_imgSrc;
      ++pb_imgMask;
    }
    pf_imgSrc += imgSrcOffset;
    pb_imgMask += imgMaskOffset;
  }
  return pixValues;
}

编辑** 以下是我想要做的方式:

private static unsafe List<PixelF> GetPixels<Timg, Tmask>(
  VMImage img, 
  int band, 
  VMImage imgMask, 
  int bandMask)
{
  List<PixelF> pixValues = new List<PixelF>();
  int r, c;
  int imgSrcOffset = img.LineLength - img.Width;
  int imgMaskOffset = imgMask.LineLength - imgMask.Width;
  Timg* pf_imgSrc = (Timg*)img.GetRoiPointer(band);
  Tmask* pb_imgMask = (Tmask*)imgMask.GetRoiPointer(bandMask);
  for (r = 0; r < img.Height; r++) // Loop over rows
  {
    for (c = 0; c < img.Width; c++) // Loop over columns
    {
      if (*pb_imgMask > 0)
      {
        pixValues.Add(new PixelF(c, r, (float)*pf_imgSrc));
      }
      ++pf_imgSrc;
      ++pb_imgMask;
    }
    pf_imgSrc += imgSrcOffset; 
    pb_imgMask += imgMaskOffset;
  }
  return pixValues;
}

我希望您能够做C++模板相关的工作,但是否可能在C#中实现?
编辑***
正如shambulator所指出的那样,仅尝试执行
private static unsafe GetPixels_ByteImg_FloatMask<TImg, TMask>(
  VMImage img, 
  int band, 
  VMImage imgMask, 
  int bandMask) 
    where TImg : struct where TMask : struct
    {
      TImg* pb_imgSrc = (TImg*)img.GetRoiPointer(band);
    }

给出错误信息(无法获取托管类型的地址、大小或声明指向托管类型的指针)。
编辑*:基本上,我需要知道指针的大小(byte、short、float),当然,它必须正确地转换为float后使用。

1
是的,原始类型可以用作通用类型参数。例如,List<int> 是常见的。 - Pieter Geerkens
听起来你说的“primitive types”指的是值类型。如果是这样,那么你遇到了什么问题?泛型适用于值类型和引用类型(甚至可以限制泛型只能是其中之一)。 - Brian Ball
但是,你想做的不是通用的。通用类型可以是原始值类型,当然也可以是任何其他类型,除非你应用了约束。 - Jodrell
好的,我需要澄清一下,这行代码 float* pf_imgSrc = (float*)img.GetRoiPointer(band); 应该变成类似这样的 TImg* pf_imgSrc = (Timg*)img.GetRoiPointer(band); - buildcomplete
你需要再澄清一下。经过一些代码实验,发现如果添加一个泛型类型参数 T,问题的根源似乎在于无法声明 T* pf_imgSrc无法获取托管类型的地址、大小或声明指向托管类型的指针)。即使使用 struct 泛型约束也不行。 - anton.burger
@shambulator 是的,我注意到了,我会去做的。 - buildcomplete
1个回答

2

我的建议是在单独的托管C++程序集中完成此操作,也就是C++/CLI,其中公共的.NET API公开了您的通用类型接口,而与“不安全”指针相关的内容发生在本地代码中。


这是一个好主意,但我担心在我们公司无法推销它,因为我们非常坚持将所有东西都转换为C#,而不是C ++。如果可能的话,是否能够使用anyCPU来创建这个Managed C++包装器呢?如果可以的话,那将是一个很好的卖点。 - buildcomplete
不行,但你可以按照这里概述的步骤(http://scottbilas.com/blog/automatically-choose-32-or-64-bit-mixed-mode-dlls/)自动加载正确的本地库。我想你不能两全其美:既使用不安全指针,又只用C#... - Menno Deij - van Rijswijk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接