我想创建一个可以有效地将单个对象包装为IEnumerables的扩展方法。这是为了避免最终将new [] {}
放在表达式中间的情况。这很容易使用以下方法:
public static IEnumerable<TSource> WrapAsEnumerable<TSource>(this TSource source)
{
return new[] { source };
}
问题是这将应用于任何和所有类型(这是预期的行为),但这也会产生使IEnumerable <T>
实例上的方法可用的副作用。在解析的扩展类型是IEnumerable<T>
的情况下,我只想返回这个IEnumerable,因为替代者发现自己的IEnumerable<IEnumerable<T>>
,这不是你在调用时所期望的方法。
本能地(也许是睡不着觉),我首先创建了一个看起来像这样的重载
public static IEnumerable<TSource> WrapAsEnumerable<TSource>(this IEnumerable<TSource> source)
{
return source;
}
为了处理要包装的类型是IEnumerable<T>
的情况,但是当然,控制流总是解析为第一种方法。
所以,问题是:我怎样才能创建这样一个包装方法来处理扩展参数实例为IEnumerable<T>
的情况和何时不处理?
答案 0 :(得分:3)
这是另一个尝试,灵感来自Eric Lippert在https://stackoverflow.com/a/1451184/4955425的优秀帖子。
您可以通过将2个扩展方法放在命名空间层次结构中的不同级别来控制重载分辨率。
using MyExtensions;
using MyExtensions.LowerPrecedenceNamespace;
但是,缺点是你总是需要引用两个命名空间来获得正确的方法调用行为。
DB.Run()
答案 1 :(得分:1)
您是否考虑过更改签名,使代码更复杂但使用非常简单。
public static class Extensions
{
public static IEnumerable<TSource> WrapAsEnumerable<TSource>(this object source)
{
var allInterfaces = source.GetType().GetInterfaces();
IEnumerable<Type> allEnumerableInterfaces = allInterfaces.Where(t => t.Name.StartsWith("IEnumerable"));
if (!allEnumerableInterfaces.Any())
return new[] { (TSource)source };
IEnumerable<Type> genericEnumerableOfTSource = allEnumerableInterfaces.Where(t => t.GenericTypeArguments.Contains(typeof(TSource)));
// we have a generic implementation
if (genericEnumerableOfTSource.Any())
{
return (IEnumerable<TSource>) source;
}
return new[] { (TSource)source }; ;
}
}
[TestFixture]
public class Tests
{
[Test]
public void should_return_string_an_enumerable()
{
const string aString = "Hello World";
var wrapped = aString.WrapAsEnumerable<string>();
wrapped.ShouldAllBeEquivalentTo(new[] {"Hello World"});
}
[Test]
public void should_return_generic_enumerable_unwrapped()
{
var aStringList = new List<string> { "Hello", "World" };
var wrapped = aStringList.WrapAsEnumerable<string>();
wrapped.ShouldAllBeEquivalentTo(new[] { "Hello", "World" });
}
[Test]
public void should_return_non_generic_enumerable_unwrapped()
{
var aStringArray = new[] {"Hello", "World"};
var wrapped = aStringArray.WrapAsEnumerable<string>();
wrapped.ShouldAllBeEquivalentTo(new[] { "Hello", "World" });
}
}