【问题标题】:Why is pointer to generic types not allowed?为什么不允许指向泛型类型的指针?
【发布时间】:2017-03-21 23:22:41
【问题描述】:

例如作为重载的[]setter-getter,

    public T this[int i]
    {
        get
        {
            unsafe
            {
                T* p = (T*)hArr.ToPointer(); // hArr is a C++ object pointer(IntPtr)
                return *(p + i);
            }

        }
        set
        {
            unsafe
            {
                T* p = (T*)hArr.ToPointer();
                *(p + i) = value;
            }
        }
    }

并且编译器抱怨(下划线)它“无法将...的地址”转换为托管类型T

我知道T 在运行时只会是浮点、双精度、整数或字节,但我不知道如何告诉编译器,所以它信任我。

为什么我不能用,反正都是指针,一不小心我可以溢出任何类型的数组。

我怎样才能做到这一点(用类似的方式或其他方式)而不比:

    public float this[int i]
    {
        get
        {
            unsafe
            {
                float* p = (float*)hArr.ToPointer();
                return *(p + i);
            }

        }
        set {
            unsafe
            {
                float* p = (float*)hArr.ToPointer();
                *(p + i) = value;
            }
        }
    }

我不仅关心这里的性能,还关心代码的简单性。 (所有 T 类型的一个代码)我想接口在这里无济于事。

【问题讨论】:

  • 不能使用引用类型的& 运算符(不包括string 类型)来获取指针...值类型(struct)可以包含引用类型,所以一般来说你不能做 T& (因为即使将 T 限制为值类型,拥有指向它的指针仍然可能是“非法的”)
  • @xanatos 我也不能继承浮点数或整数。这是否意味着,我必须在代码重复 + 性能与简单性 + not_performance 之间做出选择?
  • @huseyn 可能如你所说。也许您可以直接用 IL 代码编写它,并拥有一个仅由 IL 代码组成的程序集......已经有一个像这样完成的库
  • @xanatos 有 aparapi 和 cudafy 相似,但我正在为非常简单的事情编写一个非常简单的库。
  • 我说的是:用 IL 语言编写的库 github.com/dotnet/corefx/tree/master/src/…

标签: c# pointers generics


【解决方案1】:

C# restricts 指向的指针类型

  • sbyte, byte, short, ushort, int, uint, long, ulong, char, @9876543332@, double, @98765434 987654334@,
  • 任何enum 类型,
  • 任何指针类型,
  • 任何用户定义的struct 类型,仅包含非托管类型的字段。

最后一点是关键,因为编译器必须能够验证您尝试指向的 struct 是否“合法”。否则,您将能够传递 T,即 struct,其中的字段引用托管类型(例如,string),这是被禁止的。

由于您有兴趣为四种数据类型提供此行为,您应该能够通过提供四种重载来解决此问题:

public int GetInt(int i) {
    unsafe {
        var p = (int*)hArr.ToPointer();
        return *(p + i);
    }
public void SetInt(int i, int val) {
    unsafe {
        var p = (int*)hArr.ToPointer();
        *(p + i) = val;
    }
}
public float GetFloat(int i) {
    unsafe {
        var p = (int*)hArr.ToPointer();
        return *(p + i);
    }
public void SetFloat(int i, float val) {
    unsafe {
        var p = (float*)hArr.ToPointer();
        *(p + i) = val;
    }
}
... // and so on

假设编译器在编译时有足够的信息来解决重载,运行时效率将保持不变。

【讨论】:

  • 那么如果我在 C++ 部分重载,然后 C# 部分只需要一个参数来告诉对象类型,并且只使用带有数组和参数字段的结构就足够清楚了吗?
  • @huseyintugrulbuyukisik 是的,类型指示符字段应该可以正常工作。不幸的是,由于相当严格的规则,没有干净的方法让它与指针一起工作。
猜你喜欢
  • 2021-12-31
  • 2012-08-15
  • 2010-10-22
  • 2015-10-09
  • 1970-01-01
  • 1970-01-01
  • 2017-10-28
  • 1970-01-01
相关资源
最近更新 更多