【问题标题】:C# cast exception in C# dllC# dll 中的 C# 强制转换异常
【发布时间】:2017-03-21 20:39:00
【问题描述】:

我有一个类,其字段分配给类型为 T 的数组或类型为 T 的 dll 对象,该对象具有 this [int i] 的重载以模仿数组(它使用非托管内存并使用重载访问)

    public T this[int i]
    {
        get
        {
            return ((T[])array)[i]; // can't use return array[i] directly
        }
        set { }
    }

当我使用 dll 对象时,它会抛出强制转换异常。我认为(T[]) 会触发对象的重载[],而不是转换为float[],但它总是转换为float[],并且对象类型是FloatArr,其中有public float this[int i]。

有没有办法将原始数组视为强制转换,同时将其他自定义类型视为重载触发器?

如果这是不可能的,如何返回类型T 而返回类型如float 可以从一个简单的浮点数组或一些具有重载返回浮点的自定义类型中收集?我不想一一添加 float,int,byte,double,char,...。无论对象字段是 C# 数组还是带有重载索引器的自定义类型,我都需要 type T 工作?

我真正需要的:

    // developer supplies here with his/hers own array
    // or this library uses its own fast C++ wrapper with a [] overload
    public object array { get; set; }

    // returns float, int, byte
    public T this[int i]
    {
        get
        {
            return array[i]; // float[], int[], FloatArr[], ...
        }
        set { }
    }

编辑:如果这是一个糟糕的设计模式,请告诉我。我需要这个类来处理相同的属性,无论它是 C# 数组还是带有 [] 重载的 C++ 包装器 C# dll 对象。

Edit-2:这是我心中的用法:

MyArr<float> gpu = new MyArr<float>(1024);
gpu.array=new float[1024];
gpu[35]=40;

or


MyArr<float> gpu = new MyArr<float>(1024);
gpu.allocateUnManagedToArray(); // now array field is a custom object
gpu[35]=40;

Edit-3:这是我放入数组字段的自定义类:

public class FloatArr
{
    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;
            }
        }
    }
}

Edit-4:以防我不清楚:

  • 我有一个带有 [] 重载的类可以作为数组工作
  • 但它也有一个字段,有时会给出另一个重载 [] 的类!
  • 现在我只需要其他开发人员能够提供他们自己的 C# 数组,而他们不希望此类拥有自己的 C++ 包装对象。
  • 那么在这两种情况下,我都需要它[] 可从同一字段索引(浮点数组或具有[] 重载的C++ 包装器)。

当然,我可以一个一个地写下 float int 字节的所有条件,但是这样会花费更长的时间。通用类很容易,应该很容易,但我在这里遗漏了一些我看不到的东西。当我添加结构数组时,代码会越来越多,所以我无奈地需要泛型类。

【问题讨论】:

  • 我不明白...为什么不是public T[] array { get; set; }?
  • 它也可以是非托管内存包装器(作为 C++ 分配器和访问器)
  • 什么是it? T 或 T[] 由于 T 是通用的,我不知道为什么 T 不能是任何东西(托管或非托管)。
  • 为什么T[] 不 会转换为数组?这正是你告诉它要做的事情。也许您实际上想转换为IList&lt;T&gt;,然后使用提供的索引器? minimal reproducible example 在这里真的很有帮助...
  • 您需要展示一个使用自定义包装类的 Minimal、Complete 和 Verifiable 示例。您当前的示例无助于解释为什么您的自定义包装器不会强制转换,因为您的示例都没有使用包含包装器定义的有效自定义包装器。您的新 Edit2 也不包含此信息,我们需要查看 allocateUnManagedToArray() 的代码,并且我们需要查看 allocateUnManagedToArray() 在内部分配给 array 的类的完整定义。

标签: c# object indexing casting overloading


【解决方案1】:

您需要做的不是使用数组,而是使用IList&lt;T&gt; 接口。然后,您需要让您的自定义类实现该接口。

class FloatArr : IList<float>
{
    //(snip)
    // p and hArr's decliration and assignment
    //(snip)

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

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

    IEnumerator<float> IEnumerable<float>.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    void ICollection<float>.Add(float item)
    {
        throw new NotImplementedException();
    }

    void ICollection<float>.Clear()
    {
        throw new NotImplementedException();
    }

    bool ICollection<float>.Contains(float item)
    {
        throw new NotImplementedException();
    }

    void ICollection<float>.CopyTo(float[] array, int arrayIndex)
    {
        throw new NotImplementedException();
    }

    bool ICollection<float>.Remove(float item)
    {
        throw new NotImplementedException();
    }

    int ICollection<float>.Count
    {
        get { throw new NotImplementedException(); }
    }

    bool ICollection<float>.IsReadOnly
    {
        get { throw new NotImplementedException(); }
    }

    int IList<float>.IndexOf(float item)
    {
        throw new NotImplementedException();
    }

    void IList<float>.Insert(int index, float item)
    {
        throw new NotImplementedException();
    }

    void IList<float>.RemoveAt(int index)
    {
        throw new NotImplementedException();
    }
}

如果您不需要写入数组而只读取,则可以使用 IReadOnlyList&lt;T&gt; 大大简化类

class FloatArr : IReadOnlyList<float>
{
    //(snip)
    // p and hArr's decliration and assignment
    //(snip)

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

        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    IEnumerator<float> IEnumerable<float>.GetEnumerator()
    {
        throw new NotImplementedException();
    }

    int IReadOnlyCollection<float>.Count
    {
        get { throw new NotImplementedException(); }
    }
}

然后你的容器类改为

// developer supplies here with his/hers own array
// or this library uses its own fast C++ wrapper with a [] overload
public IList<T> array { get; set; }

// returns float, int, byte
public T this[int i]
{
    get
    {
        return array[i]; // float[], int[], FloatArr, ...
    }
    set
    {
        array[i] = value;
    }
}

或

// developer supplies here with his/hers own array
// or this library uses its own fast C++ wrapper with a [] overload
public IReadOnlyList<T> array { get; set; }

// returns float, int, byte
public T this[int i]
{
    get
    {
        return array[i]; // float[], int[], FloatArr, ...
    }
}

【讨论】:

  • 所以有了接口,这些都是兼容的。那么我需要让任何未来的结构类型实现 IList?
  • IList、IList&lt;T&gt; 和IReadOnlyList&lt;T&gt; 有3 个可能的接口可供选择,任何一个都可以,.net 中内置的Array 类型实现了所有3 个接口。您只需要选择一个并让将用作后备存储的类实现该接口。
  • 我觉得我仍然是 oop 编程的菜鸟。这是不是一个糟糕的设计?
  • 我还发布了第二个答案,该答案更易于编码,但比使用界面要慢得多。如果您可以选择使用接口而不是dynamic。编辑:使用接口根本不是一个糟糕的设计。它们的全部意义在于,您无需进行强制转换即可获得所需的功能。
【解决方案2】:

另一个选项,而不是实现IList&lt;T&gt; 或IReadOnlyList&lt;T&gt;,您可以使用dynamic 关键字来执行运行时绑定而不是编译时绑定。然而,这将比使用 IList&lt;T&gt; 或 IReadOnlyList&lt;T&gt; 的性能差很多

// developer supplies here with his/hers own array
// or this library uses its own fast C++ wrapper with a [] overload
public dynamic array { get; set; }

// returns float, int, byte
public T this[int i]
{
    get
    {
        return array[i]; // float[], int[], FloatArr[], ...
    }
    set 
    {
        array[i] = value;
    }
}

【讨论】:

  • 我需要我的库 3.5(或有时 2.0)兼容。所以动态可能不适合我?
  • 那么使用接口会好很多。
  • 非常感谢(Jon Skeet 之前说过,但当时我不明白)
猜你喜欢
  • 1970-01-01
  • 2020-08-16
  • 2012-09-21
  • 2012-05-28
  • 2022-06-15
  • 1970-01-01
  • 2019-04-05
  • 2023-03-19
  • 1970-01-01
相关资源
最近更新 更多