如何让自定义类具备数组特性并调用数组扩展方法?
解决自定义泛型类调用数组扩展方法的问题
首先得指出你代码里的一个小语法错误:ArrayExtensions里的Foo方法返回值写错了,应该是public static void Foo<T>(this T[] array),不是void T[],这个先修正掉。
回到你的核心问题:为什么MyArray<T>不能直接调用针对T[]的扩展方法?因为C#的扩展方法是基于编译时的静态类型匹配的——你的a是MyArray<int>(注意你实例化的时候漏了泛型参数,应该是new MyArray<int>(10)),它不是int[]类型,所以编译器找不到对应的扩展方法。
下面给你三种可行的解决方案,按需选择:
方案一:给MyArray<T>写专属的扩展方法
这是最直接的办法,直接为你的自定义类扩展对应的方法,内部复用原数组扩展方法的逻辑:
public class MyArray<T> { private T[] _array; public MyArray(int size) => _array = new T[size]; public T this[int index] { get => _array[index]; set => _array[index] = value; } // 新增一个公开的属性获取内部数组(如果不想把_array改成internal的话) public T[] UnderlyingArray => _array; } public static class ArrayExtensions { public static void Foo<T>(this T[] array) { // 原有的数组处理逻辑 Console.WriteLine("处理数组"); } } // 新增针对MyArray<T>的扩展方法 public static class MyArrayExtensions { public static void Foo<T>(this MyArray<T> myArray) { // 直接调用原数组的扩展方法 myArray.UnderlyingArray.Foo(); } } public class ArrayUser { public ArrayUser() { var a = new MyArray<int>(10); a.Foo(); // 现在可以正常编译运行了 } }
方案二:给MyArray<T>添加到T[]的隐式转换
通过隐式转换,让你的自定义类可以自动转换成数组类型,这样就能调用数组的扩展方法了:
public class MyArray<T> { private T[] _array; public MyArray(int size) => _array = new T[size]; public T this[int index] { get => _array[index]; set => _array[index] = value; } // 添加隐式转换运算符 public static implicit operator T[](MyArray<T> myArray) { return myArray._array; } } // 原ArrayExtensions保持不变 public static class ArrayExtensions { public static void Foo<T>(this T[] array) { Console.WriteLine("处理数组"); } } public class ArrayUser { public ArrayUser() { var a = new MyArray<int>(10); // 显式转换后调用,或者编译器会自动转换(视上下文而定) ((int[])a).Foo(); // 或者更简洁的写法: int[] temp = a; temp.Foo(); } }
注意:隐式转换会让类型转换变得很“隐形”,如果你的MyArray<T>有特殊的业务逻辑,这种转换可能会让代码可读性下降,所以要谨慎使用。
方案三:修改原扩展方法的参数为通用接口(如果允许的话)
如果原扩展方法的逻辑不依赖数组的特殊特性(比如直接访问内存、固定长度等),可以把它改成针对更通用的集合接口(比如IList<T>),然后让MyArray<T>实现这个接口:
public class MyArray<T> : IList<T> { private T[] _array; public MyArray(int size) => _array = new T[size]; // 实现IList<T>的所有成员,大部分可以直接委托给_array public T this[int index] { get => _array[index]; set => _array[index] = value; } public int Count => _array.Length; public bool IsReadOnly => false; public void Add(T item) => throw new NotSupportedException("固定大小的数组不支持添加"); public void Clear() => Array.Clear(_array, 0, _array.Length); public bool Contains(T item) => Array.IndexOf(_array, item) != -1; public void CopyTo(T[] array, int arrayIndex) => _array.CopyTo(array, arrayIndex); public IEnumerator<T> GetEnumerator() => ((IEnumerable<T>)_array).GetEnumerator(); public int IndexOf(T item) => Array.IndexOf(_array, item); public void Insert(int index, T item) => throw new NotSupportedException("固定大小的数组不支持插入"); public bool Remove(T item) => throw new NotSupportedException("固定大小的数组不支持删除"); public void RemoveAt(int index) => throw new NotSupportedException("固定大小的数组不支持删除"); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); } // 修改扩展方法的参数为IList<T> public static class ArrayExtensions { public static void Foo<T>(this IList<T> list) { // 调整逻辑适配IList<T> Console.WriteLine("处理集合"); } } public class ArrayUser { public ArrayUser() { var a = new MyArray<int>(10); a.Foo(); // 现在可以直接调用了 } }
这个方案的好处是扩展性更强,所有实现IList<T>的集合都能调用这个方法,但缺点是需要实现大量接口成员,而且如果原扩展方法依赖数组的特有功能(比如Array.Resize、指针操作等),这个方案就不适用了。
内容的提问来源于stack exchange,提问作者ChristmasAnon
相关产品推荐
相关产品推荐

