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...]
}
Run Code Online (Sandbox Code Playgroud)
有时我需要知道列表中所有内容的某个属性的最大值或最小值.因为"告诉不要问"我们让列表弄明白:
public class ThingList : IList<IThing>
{
public Decimal GetMaximumWeight()
{
Decimal result = 0;
foreach (IThing thing in this) {
result = Math.Max(result, thing.Weight);
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
这是非常好的.但有时我需要最小重量,有时最大速度等等.我不希望GetMaximum*()/GetMinimum*()
每一个属性都有一对.
一种解决方案是反思.像(抓住你的鼻子,强烈的代码味道!):
Decimal GetMaximum(String propertyName);
Decimal GetMinimum(String propertyName);
Run Code Online (Sandbox Code Playgroud)
有没有更好,更少臭的方法来实现这一目标?
谢谢,埃里克
编辑:@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);
Run Code Online (Sandbox Code Playgroud)
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; }
);
Run Code Online (Sandbox Code Playgroud)
(我没有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);
Run Code Online (Sandbox Code Playgroud)
这将使得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());
}
}
Run Code Online (Sandbox Code Playgroud)
结果:
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;
}
Run Code Online (Sandbox Code Playgroud)
用法:
Decimal result = list.GetMaximum(x => x.Weight);
Run Code Online (Sandbox Code Playgroud)
这是强类型和有效的.还有一些扩展方法已经完成了这一点.
归档时间: |
|
查看次数: |
43254 次 |
最近记录: |