huseyin tugrul buyukisik
huseyin tugrul buyukisik

Reputation: 11926

Why is pointer to generic types not allowed?

For example, as an overloaded [] 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;
            }
        }
    }

and compiler complains(underlines) about it "cannot take address of ..." to a managed type T.

I know T will be only float,double,int or byte in runtime but I don't know how to tell this to compiler so it trusts me.

Why can't I use it, all are pointers anyway, I can overflow any type of array if I'm not careful.

How can I achieve this(with a similar way or another) without being much slower than:

    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;
            }
        }
    }

I don't just care about performance here, but also code simplicity too. (one code for all T types) Interfaces can't help here I suppose.

Upvotes: 4

Views: 1196

Answers (1)

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726969

C# restricts pointer types to

  • sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal, or bool,
  • Any enum type,
  • Any pointer type,
  • Any user-defined struct type that contains fields of unmanaged types only.

That last point is key, because the compiler must be able to verify that the struct to which you are trying to make a pointer is "legal". Otherwise, you would be able to pass T that is a struct with fields referencing managed types (say, a string) which is prohibited.

Since you are interested in providing this behavior for four data types, you should be able to address this problem by providing four overloads:

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

The run-time efficiency will remain the same, assuming that the compiler has enough information to resolve overloads at compile time.

Upvotes: 3

Related Questions