C#:获取列表中所有项目的任意属性的最大值和最小值
我有一个专门的列表,其中包含 IThing
类型的项目:
public class ThingList : IList<IThing>
{...}
public interface IThing
{
Decimal Weight { get; set; }
Decimal Velocity { get; set; }
Decimal Distance { get; set; }
Decimal Age { get; set; }
Decimal AnotherValue { get; set; }
[...even more properties and methods...]
}
有时我需要知道列表中所有事物的某个属性的最大值或最小值。 因为“告诉不要问”,我们让列表弄清楚了:
public class ThingList : IList<IThing>
{
public Decimal GetMaximumWeight()
{
Decimal result = 0;
foreach (IThing thing in this) {
result = Math.Max(result, thing.Weight);
}
return result;
}
}
这非常好。 但有时我需要最小重量,有时需要最大速度等等。 我不希望每个属性都有一个 GetMaximum*()/GetMinimum*()
对。
一种解决方案是反思。 比如(捂住鼻子,强烈的代码气味!):
Decimal GetMaximum(String propertyName);
Decimal GetMinimum(String propertyName);
有没有更好、更少气味的方法来实现这一点?
谢谢, Eric
编辑:@Matt:.Net 2.0
结论:.Net 2.0(使用 Visual Studio 2005)没有更好的方法。 也许我们应该尽快转向.Net 3.5 和 Visual Studio 2008。 谢谢大家。
结论:有很多比反射更好的方法。 取决于运行时和 C# 版本。 看看 Jon Skeets 对差异的回答。 所有答案都非常有帮助。
我会寻求 Sklivvz 建议(匿名方法)。 其他人(Konrad Rudolph、Matt Hamilton 和 Coincoin)有几个代码片段实现了 Sklivvz 的想法。 不幸的是,我只能“接受”一个答案。
非常感谢。 你们都会感到“被接受”,尽管只有 Sklivvz 获得了荣誉;-)
I have a specialized list that holds items of type IThing
:
public class ThingList : IList<IThing>
{...}
public interface IThing
{
Decimal Weight { get; set; }
Decimal Velocity { get; set; }
Decimal Distance { get; set; }
Decimal Age { get; set; }
Decimal AnotherValue { get; set; }
[...even more properties and methods...]
}
Sometimes I need to know the maximum or minimum of a certain property of all the things in the list. Because of "Tell don't ask" we let the List figure it out:
public class ThingList : IList<IThing>
{
public Decimal GetMaximumWeight()
{
Decimal result = 0;
foreach (IThing thing in this) {
result = Math.Max(result, thing.Weight);
}
return result;
}
}
Thats very nice. But sometimes I need the minimum weight, sometimes the maximum velocity and so on. I don't want a GetMaximum*()/GetMinimum*()
pair for every single property.
One solution would be reflection. Something like (hold your nose, strong code smell!):
Decimal GetMaximum(String propertyName);
Decimal GetMinimum(String propertyName);
Are there any better, less smelly ways to accomplish this?
Thanks,
Eric
Edit: @Matt: .Net 2.0
Conclusion: There is no better way for .Net 2.0 (with Visual Studio 2005). Maybe we should move to .Net 3.5 and Visual Studio 2008 sometime soon. Thanks, guys.
Conclusion: There are diffent ways that are far better than reflection. Depending on runtime and C# version. Have a look at Jon Skeets answer for the differences. All answers are are very helpful.
I will go for Sklivvz suggestion (anonymous methods). There are several code snippets from other people (Konrad Rudolph, Matt Hamilton and Coincoin) which implement Sklivvz idea. I can only "accept" one answer, unfortunately.
Thank you very much. You can all feel "accepted", altough only Sklivvz gets the credits ;-)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
(编辑以反映.NET 2.0答案,以及VS2005中的LINQBridge...)
这里有三种情况 - 虽然OP只有.NET 2.0,但面临同样问题的其他人可能没有...
1)使用.NET 3.5和C# 3.0:使用 LINQ to Objects,如下所示:
2) 使用 .NET 2.0 和 C# 3.0:使用 LINQBridge< /a> 和相同的代码
3) 使用 .NET 2.0 和 C# 2.0:使用 LINQBridge和匿名方法:(
我没有 C# 2.0 编译器来测试上述内容 - 如果它抱怨转换不明确,请将委托强制转换为 Func。)
LINQBridge 将与 VS2005 一起使用,但您不这样做没有扩展方法、lambda 表达式、查询表达式等。显然,迁移到 C# 3 是一个更好的选择,但我更喜欢使用 LINQBridge 自己实现相同的功能。
如果您需要同时获得最大值和最小值,所有这些建议都涉及遍历列表两次。 如果您遇到从磁盘延迟加载或类似情况的情况,并且您想一次性计算多个聚合,您可能需要查看我的 "推送 LINQ" 代码在 MiscUtil 中。 (这也适用于 .NET 2.0。)
(Edited to reflect .NET 2.0 answer, and LINQBridge in VS2005...)
There are three situations here - although the OP only has .NET 2.0, other people facing the same problem may not...
1) Using .NET 3.5 and C# 3.0: use LINQ to Objects like this:
2) Using .NET 2.0 and C# 3.0: use LINQBridge and the same code
3) Using .NET 2.0 and C# 2.0: use LINQBridge and anonymous methods:
(I don't have a C# 2.0 compiler to hand to test the above - if it complains about an ambiguous conversion, cast the delegate to Func<IThing,decimal>.)
LINQBridge will work with VS2005, but you don't get extension methods, lambda expressions, query expressions etc. Clearly migrating to C# 3 is a nicer option, but I'd prefer using LINQBridge to implementing the same functionality myself.
All of these suggestions involve walking the list twice if you need to get both the max and min. If you've got a situation where you're loading from disk lazily or something like that, and you want to calculate several aggregates in one go, you might want to look at my "Push LINQ" code in MiscUtil. (That works with .NET 2.0 as well.)
如果您使用 .NET 3.5 和 LINQ:
这将使 Min 和 Max 的计算变得相当简单。
If you were you using .NET 3.5 and LINQ:
That would make the calculation of Min and Max fairly trivial.
是的,您应该使用委托和匿名方法。
有关示例,请参阅此处。
基本上,您需要实现类似于 Find 列表方法。
以下是示例实现
结果:
按日期排列的最大值:I: 4, S: w, D: 10/3/2008 12:44:07 AM
最小字符:I:5,S:v,D:9/29/2008 12:44:07 AM
Yes, you should use a delegate and anonymous methods.
For an example see here.
Basically you need to implement something similar to the Find method of Lists.
Here is a sample implementation
The results:
Max by date: I: 4, S: w, D: 10/3/2008 12:44:07 AM
Min by char: I: 5, S: v, D: 9/29/2008 12:44:07 AM
如果使用 .NET 3.5,为什么不使用 lambda?
用法:
这是强类型且高效的。 还有一些扩展方法已经可以做到这一点。
If using .NET 3.5, why not use lambdas?
Usage:
This is strongly typed and efficient. There are also extension methods that already do exactly this.
对于 C# 2.0 和 .Net 2.0,您可以对 Max 执行以下操作:
以下是您将如何使用它:
以下是您如何使用 C# 3.0、.Net 3.5 和 Linq(没有上述函数)执行此操作:
For C# 2.0 and .Net 2.0 you can do the following for Max:
And here is how you would use it:
Here is how you would do it with C# 3.0, .Net 3.5 and Linq, without the function above:
这是根据 Skilwz 的想法使用 C# 2.0 进行的尝试。
你会像这样使用它:
Here's an attempt, using C# 2.0, at Skilwz's idea.
You'd use it like this:
您似乎误解了答案(尤其是 Jon 的答案)。 您可以使用他的答案中的选项 3。如果您不想使用 LinqBridge,您仍然可以使用委托并自己实现Max
方法,类似于我发布的方法:用法:
You seem to have misunderstood the answers (especially Jon's). You can use option 3 from his answer.If you don't want to use LinqBridge you can still use a delegate and implement theMax
method yourself, similar to the method I've posted:Usage:
通用的 .Net 2 解决方案怎么样?
How about a generalised .Net 2 solution?