限制 IList<T> 扩展方法以排除数组
Restrict an IList<T> extension method to exclude Arrays
假设我为 IList 创建了一个扩展方法,但这个扩展是一个可能在许多项目中使用的库的一部分。我无法控制它的调用方式。
有没有办法阻止 Array
在编译时调用 IList<T>
扩展方法?这是为了避免任何误用,如果将调用 .Add() 方法或仅调用索引器,则调用者无法猜测确切的实现。
我找不到具有通用约束类型的可能解决方案。
到目前为止,剩下的唯一可能就是将扩展方法直接限制为 List<T>
。
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var array = new[]{"Hello"};
array.DummyInsert("World"); // this will crash at run time
}
}
public static class DummyExtension
{
public static T DummyInsert<T>(this IList<T> list, T insertValue)
{
list.Add(insertValue);
return insertValue;
}
}
我同意 Ed Plunkett 的观点,使用 ReadOnlyCollection<T>
。但是你可以这样做。是你的脚,你想拍就拍。
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var array = new[]{"Hello"};
var world = array.Insert("World"); // this will crash at run time
Console.WriteLine(array.Length);
}
}
public static class DummyExtension
{
public static T Insert<T>(this IList<T> list, T insertValue)
{
Console.WriteLine("WrongInsert");
list.Add(insertValue);
return insertValue;
}
[Obsolete("If want a compile time exception you can do this too.", true)]
public static T Insert<T>(this T[] list, T insertValue)
{
Console.WriteLine("RightInsert");
return insertValue;
}
}
这会打印
RightInsert
1
https://dotnetfiddle.net/i6p1Z5
编辑:
有人在下面的评论中指出,如果您的数组已显式或隐式转换为 IList<T>
,这将不起作用。在这里使用 List<T>
而不是 IList<T>
没有任何问题,除非你试图实际扩展 IList<T>
。在那种情况下,以一种对所有人都有意义的方式扩展它 IList<T>
。我只是想表明,是的,您可以完成您的要求。能力越大,责任越大。
运行-time 问题是因为 Array 是固定长度的,因此当您尝试向其中插入一个元素时,您最终会遇到异常。相反,您可以为 case Array 使用自己的扩展方法并相应地处理插入。
public class Program
{
public static void Main()
{
var array = new[] { "Hello" };
array = array.Insert("World");
}
}
public static class DummyExtension
{
public static T Insert<T>(this IList<T> list, T insertValue)
{
list.Add(insertValue);
return insertValue;
}
public static T[] Insert<T>(this T[] list, T insertValue)
{
var destArray = new T[list.Length + 1];
Array.Copy(list, destArray, list.Length);
destArray[destArray.Length - 1] = insertValue;
return destArray;
}
}
好吧,我同意这可能是一种粗略的方法,但它适用于您的情况。
您可以将扩展方法添加到 List<T>
而不是 IList<T>
假设我为 IList 创建了一个扩展方法,但这个扩展是一个可能在许多项目中使用的库的一部分。我无法控制它的调用方式。
有没有办法阻止 Array
在编译时调用 IList<T>
扩展方法?这是为了避免任何误用,如果将调用 .Add() 方法或仅调用索引器,则调用者无法猜测确切的实现。
我找不到具有通用约束类型的可能解决方案。
到目前为止,剩下的唯一可能就是将扩展方法直接限制为 List<T>
。
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var array = new[]{"Hello"};
array.DummyInsert("World"); // this will crash at run time
}
}
public static class DummyExtension
{
public static T DummyInsert<T>(this IList<T> list, T insertValue)
{
list.Add(insertValue);
return insertValue;
}
}
我同意 Ed Plunkett 的观点,使用 ReadOnlyCollection<T>
。但是你可以这样做。是你的脚,你想拍就拍。
using System;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var array = new[]{"Hello"};
var world = array.Insert("World"); // this will crash at run time
Console.WriteLine(array.Length);
}
}
public static class DummyExtension
{
public static T Insert<T>(this IList<T> list, T insertValue)
{
Console.WriteLine("WrongInsert");
list.Add(insertValue);
return insertValue;
}
[Obsolete("If want a compile time exception you can do this too.", true)]
public static T Insert<T>(this T[] list, T insertValue)
{
Console.WriteLine("RightInsert");
return insertValue;
}
}
这会打印
RightInsert
1
https://dotnetfiddle.net/i6p1Z5
编辑:
有人在下面的评论中指出,如果您的数组已显式或隐式转换为 IList<T>
,这将不起作用。在这里使用 List<T>
而不是 IList<T>
没有任何问题,除非你试图实际扩展 IList<T>
。在那种情况下,以一种对所有人都有意义的方式扩展它 IList<T>
。我只是想表明,是的,您可以完成您的要求。能力越大,责任越大。
运行-time 问题是因为 Array 是固定长度的,因此当您尝试向其中插入一个元素时,您最终会遇到异常。相反,您可以为 case Array 使用自己的扩展方法并相应地处理插入。
public class Program
{
public static void Main()
{
var array = new[] { "Hello" };
array = array.Insert("World");
}
}
public static class DummyExtension
{
public static T Insert<T>(this IList<T> list, T insertValue)
{
list.Add(insertValue);
return insertValue;
}
public static T[] Insert<T>(this T[] list, T insertValue)
{
var destArray = new T[list.Length + 1];
Array.Copy(list, destArray, list.Length);
destArray[destArray.Length - 1] = insertValue;
return destArray;
}
}
好吧,我同意这可能是一种粗略的方法,但它适用于您的情况。
您可以将扩展方法添加到 List<T>
而不是 IList<T>