4

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.

huseyin tugrul buyukisik
  • 11,469
  • 4
  • 45
  • 97
  • You can't take a pointer with the `&` operator of reference types (excluding the `string` type)... A value type (a `struct`) can contain a reference type, so in general you can't do a `&` of a `T` (because even restricting `T` to a value type, it could still be "illegal" to have a pointer to it) – xanatos Mar 21 '17 at 23:27
  • @xanatos also I can't inherit float or int. Does this mean, I must choose between code duplication + performance versus simplicity + not_performance here? – huseyin tugrul buyukisik Mar 21 '17 at 23:29
  • @huseyn Probably as you said. Perhaps you can write it in IL code directly and have an assembly composed only of IL code... There is already a library done like this – xanatos Mar 21 '17 at 23:31
  • @xanatos there are aparapi and cudafy similar but I'm writing a very simple library for very simple things. – huseyin tugrul buyukisik Mar 21 '17 at 23:34
  • What I was speaking about: a library written in IL language https://github.com/dotnet/corefx/tree/master/src/System.Runtime.CompilerServices.Unsafe/src – xanatos Mar 22 '17 at 07:26

1 Answers1

3

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.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • Then if I overload in C++ part instead and then C# part would need only a parameter telling object type and be clear enough using just a struct with array and a parameter field? – huseyin tugrul buyukisik Mar 21 '17 at 23:36
  • @huseyintugrulbuyukisik Yes, a type designator field should work fine. Unfortunately, there's no clean way to make it work with pointers, because of rather strict rules. – Sergey Kalinichenko Mar 21 '17 at 23:40