C# 有时(它在编译时是一个对象),它变得非常困难。
C# 有时(它在编译时是一个对象),它变得非常困难。,c#,linq,generics,C#,Linq,Generics,首先不接受选择器,它接受谓词。要将选择器应用于第一项,需要获取第一项(使用其无参数重载),然后对该结果调用选择器 要比较未知类型的对象是否相等,您将无法使用=运算符。它是在编译时绑定的,因此它不能说明该类型的特定实现,而且它可能没有。您应该使用IEqualityComparer来比较项目是否相等(如果未提供任何比较器,则可以使用默认比较器) 还请注意,您的实现将源可枚举项迭代最多3次。如果它实际上是一个查询,而不是一个已经物化的集合,那么这很容易成为一个问题。您最好直接迭代序列,而不是在这里使用
首先
不接受选择器,它接受谓词。要将选择器应用于第一项,需要获取第一项(使用其无参数重载),然后对该结果调用选择器
要比较未知类型的对象是否相等,您将无法使用=
运算符。它是在编译时绑定的,因此它不能说明该类型的特定实现,而且它可能没有。您应该使用IEqualityComparer
来比较项目是否相等(如果未提供任何比较器,则可以使用默认比较器)
还请注意,您的实现将源可枚举项迭代最多3次。如果它实际上是一个查询,而不是一个已经物化的集合,那么这很容易成为一个问题。您最好直接迭代序列,而不是在这里使用LINQ操作,因为您不能只使用一个LINQ查询。
首先
不接受选择器,它接受谓词。要将选择器应用于第一项,需要获取第一项(使用其无参数重载),然后对该结果调用选择器
要比较未知类型的对象是否相等,您将无法使用=
运算符。它是在编译时绑定的,因此它不能说明该类型的特定实现,而且它可能没有。您应该使用IEqualityComparer
来比较项目是否相等(如果未提供任何比较器,则可以使用默认比较器)
还请注意,您的实现将源可枚举项迭代最多3次。如果它实际上是一个查询,而不是一个已经物化的集合,那么这很容易成为一个问题。您最好只是显式地迭代序列,而不是在这里使用LINQ操作,因为您不能只使用一个LINQ查询。这听起来有点混乱。e、 g.“红色”的平均值是多少?你可以让你的方法签名是
公共静态TSource AllEqual…
@stuartd,因为在这种情况下,TSource将是typeof(string),我希望它返回不同值的串联。这听起来有点混乱。e、 g.“红色”的平均值是多少?您可以将方法签名设置为公共静态TSource AllEqual…
@stuartd,因为TSource将是typeof(string)在这种情况下,我希望它返回不同值的串联。在计算平均值之前执行distinct
,会完全弄乱平均值。我知道,也说过这一点。不管怎样,它现在是固定的。在计算平均值之前执行Distinct
,会完全弄乱平均值。我知道,也说过这句话。反正现在已经修好了。
public class Item
{
public int Size {get; set;}
public string Name {get; set;}
}
var itemsTheSame = new List<Item>
{
new Item { Size = 1, Name = "Red" },
new Item { Size = 1, Name = "Red" },
new Item { Size = 1, Name = "Red" }
};
itemsTheSame.AllEqual(item => item.Size)); // should return 1 as an int
itemsTheSame.AllEqual(item => item.Name)); // should return "Red" as a string
public static class Extensions
{
public static int AllEqual<TSource>(this IEnumerable<TSource> list, Func<TSource, int> selector)
{
if (!list.Any()) return default(int);
var first = list.First();
return list.Skip(1).All(selector == first) ? default(int) : default(int);
}
}
public static TReturn AllEqual<TSource, TReturn>(this IEnumerable<TSource> list, Func<TSource, TReturn> selector)
{
if (!list.Any()) return default(TReturn);
var first = list.First(selector);
return list.Skip(1).All(selector == first) ? default(TReturn) : default(TReturn);
}
// for doubles (returning average or default if list is empty)
public static double AllEqual<TSource>(this IEnumerable<TSource> list, Func<TSource, double> selector)
{
// use IList<T> interface to quickly check the size of the
// list if this interface is available. Use ToArray otherwise.
var ilist = list as IList<TSource> ?? list.ToArray();
if (ilist.Count == 0) return 0.0;
list.Select(selector).Average();
}
// for ints (returning average or default if list is empty)
public static double AllEqual<TSource>(this IEnumerable<TSource> list, Func<TSource, int> selector)
{
// use IList<T> interface to quickly check the size of the
// list if this interface is available. Use ToArray otherwise.
var ilist = list as IList<TSource> ?? list.ToArray();
if (ilist.Count == 0) return 0.0;
list.Select(selector).Average();
}
// for everything else (returning unique value or default)
public static TReturn AllEqual<TSource, TReturn>(this IEnumerable<TSource> list, Func<TSource, TReturn> selector)
{
// put 2 distinct values into an array
var distinctItems.Select(selector).Distinct().Take(2).ToArray();
if (distinct.Length == 1) return distinct[0];
default(TReturn);
}