C#中:获取列表中的所有项目的任意属性的最大值和最小值最大值、属性、最小值、项目

2023-09-03 09:14:13 作者:繁华以落〃花下的悲伤。

我有一个专门的列表保存类型为 IThing 的项目:

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;
    }
}

那是非常好的。但有时我需要的最小重量,有时最大速度等。我不希望有一个 GetMaximum *()/ GetMinimum *()对每一个单独的属性。

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.

一个解决办法是反思。喜欢的东西(捏住鼻子,强code味道!)

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?

谢谢, 埃里克

编辑:@ 马特:NET 2.0

@Matt: .Net 2.0

结论:对于.NET 2.0没有更好的办法(与Visual Studio 2005)。也许我们应该移动到.NET 3.5和Visual Studio 2008年的某个时候推出。谢谢你,伙计们。

结论:有diffent方式远比反映好。根据运行时和C#版本。看一看的差异乔恩长柄水杓答案。所有的答案都非常有帮助的。

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.

我会去Sklivvz建议(匿名方法)。还有其他几个人的code段(康拉德·鲁道夫,马特·汉密尔顿和Coincoin)的实施Sklivvz想法。我只能接受一个答案,很遗憾。

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.

非常感谢你。你可以都觉得接受,altough只Sklivvz得到信贷; - )

Thank you very much. You can all feel "accepted", altough only Sklivvz gets the credits ;-)

推荐答案

是的,你应该使用一个代理和匿名方法。

Yes, you should use a delegate and anonymous methods.

有关的例子请参见这里。

基本上你需要实现类似于查找方法的东西的名单的。

Basically you need to implement something similar to the Find method of Lists.

下面是一个简单的执行

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());				
	}
}

结果:

最大按日期:I:4,S:W,D:2008年10月3号上午12点44分零七秒 闵成炭:我:5,S:V,D:2008年9月29日上午12点44分○七秒