Eri*_*fer 18 .net c# reflection .net-2.0
我有一个专门的列表,其中包含以下类型的项目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);
有没有更好,更少臭的方法来实现这一目标?
谢谢,埃里克
编辑:@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获得学分;-)
Jon*_*eet 32
(编辑反映.NET 2.0的答案,以及VS2005中的LINQBridge ...)
这里有三种情况 - 虽然OP只有.NET 2.0,但其他遇到同样问题的人可能不会......
1)使用.NET 3.5和C#3.0:像这样使用LINQ to Objects:
decimal maxWeight = list.Max(thing => thing.Weight);
decimal minWeight = list.Min(thing => thing.Weight);
2)使用.NET 2.0和C#3.0:使用LINQBridge和相同的代码
3)使用.NET 2.0和C#2.0:使用LINQBridge和匿名方法:
decimal maxWeight = Enumerable.Max(list, delegate(IThing thing) 
    { return thing.Weight; }
);
decimal minWeight = Enumerable.Min(list, delegate(IThing thing)
    { return thing.Weight; }
);
(我没有C#2.0编译器来测试上面的内容 - 如果它抱怨模糊的转换,请将委托转换为Func <IThing,decimal>.)
LINQBridge将与VS2005一起使用,但是你没有获得扩展方法,lambda表达式,查询表达式等.显然,迁移到C#3是一个更好的选择,但我更喜欢使用LINQBridge自己实现相同的功能.
如果您需要同时获得最大值和最小值,所有这些建议都涉及将列表移动两次.如果你有一种情况,你从懒惰的磁盘或类似的东西加载,并且你想一次性计算几个聚合,你可能想看看我在MiscUtil中的"推送LINQ"代码.(也适用于.NET 2.0.)
Mat*_*ton 19
如果您使用的是.NET 3.5和LINQ:
Decimal result = myThingList.Max(i => i.Weight);
这将使得Min和Max的计算相当微不足道.
Skl*_*vvz 10
是的,您应该使用委托和匿名方法.
举个例子,请看这里.
这是一个示例实现
public class Thing
{
    public int theInt;
    public char theChar;
    public DateTime theDateTime;
    public Thing(int theInt, char theChar, DateTime theDateTime)
    {
        this.theInt = theInt;
        this.theChar = theChar;
        this.theDateTime = theDateTime;
    }
    public string Dump()
    {
        return string.Format("I: {0}, S: {1}, D: {2}", 
            theInt, theChar, theDateTime);
    }
}
public class ThingCollection: List<Thing>
{
    public delegate Thing AggregateFunction(Thing Best, 
                        Thing Candidate);
    public Thing Aggregate(Thing Seed, AggregateFunction Func)
    {
        Thing res = Seed;
        foreach (Thing t in this) 
        {
            res = Func(res, t);
        }
        return res;
    }
}
class MainClass
{
    public static void Main(string[] args)
    {
        Thing a = new Thing(1,'z',DateTime.Now);
        Thing b = new Thing(2,'y',DateTime.Now.AddDays(1));
        Thing c = new Thing(3,'x',DateTime.Now.AddDays(-1));
        Thing d = new Thing(4,'w',DateTime.Now.AddDays(2));
        Thing e = new Thing(5,'v',DateTime.Now.AddDays(-2));
        ThingCollection tc = new ThingCollection();
        tc.AddRange(new Thing[]{a,b,c,d,e});
        Thing result;
        //Max by date
        result = tc.Aggregate(tc[0], 
            delegate (Thing Best, Thing Candidate) 
            { 
                return (Candidate.theDateTime.CompareTo(
                    Best.theDateTime) > 0) ? 
                    Candidate : 
                    Best;  
            }
        );
        Console.WriteLine("Max by date: {0}", result.Dump());
        //Min by char
        result = tc.Aggregate(tc[0], 
            delegate (Thing Best, Thing Candidate) 
            { 
                return (Candidate.theChar < Best.theChar) ? 
                    Candidate : 
                    Best; 
            }
        );
        Console.WriteLine("Min by char: {0}", result.Dump());               
    }
}
结果:
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,为什么不使用lambdas?
public Decimal GetMaximum(Func<IThing, Decimal> prop) {
    Decimal result = Decimal.MinValue;
    foreach (IThing thing in this)
        result = Math.Max(result, prop(thing));
    return result;
}
用法:
Decimal result = list.GetMaximum(x => x.Weight);
这是强类型和有效的.还有一些扩展方法已经完成了这一点.
| 归档时间: | 
 | 
| 查看次数: | 43254 次 | 
| 最近记录: |