Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#:获取列表中所有项的任意属性的最大值和最小值_C#_.net_Reflection_.net 2.0 - Fatal编程技术网

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

C#:获取列表中所有项的任意属性的最大值和最小值,c#,.net,reflection,.net-2.0,C#,.net,Reflection,.net 2.0,我有一个专门的列表,其中包含类型为I的项目: 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 Anot

我有一个专门的列表,其中包含类型为
I的项目

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...]
}
有没有更好的、不那么难闻的方法来实现这一点

谢谢, 埃里克

编辑:@Matt:.Net 2.0

结论:对于.NET2.0(使用VisualStudio2005),没有更好的方法。也许我们应该尽快转向.NET3.5和VisualStudio2008。谢谢,伙计们

结论:有许多不同的方法比反思更好。取决于运行时和C#版本。看看Jon Skeets对差异的回答。所有的答案都很有帮助

我会选择Sklivz建议(匿名方法)。有几个其他人(康拉德·鲁道夫、马特·汉密尔顿和科因科因)的代码片段实现了斯克利夫茨的想法。不幸的是,我只能“接受”一个答案


多谢各位。你们都会感到“被接受”,尽管只有斯克利夫兹获得了积分;-)

如果您使用的是.NET 3.5和LINQ:

Decimal result = myThingList.Max(i => i.Weight);

这将使最小值和最大值的计算变得相当简单。

如果使用.NET3.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;
}
这是强类型且高效的。还有一些扩展方法已经做到了这一点。

(编辑以反映.NET2.0答案,以及VS2005中的LINQBridge…)

这里有三种情况-虽然OP只有.NET2.0,但其他面临相同问题的人可能不会

1) 使用.NET 3.5和C#3.0:将LINQ用于以下对象:

decimal maxWeight = list.Max(thing => thing.Weight);
decimal minWeight = list.Min(thing => thing.Weight);
ThingList list;
Decimal maxWeight = list.GetMaximum(delegate(IThing t) { return t.Weight; });
2) 使用.NET2.0和C#3.0:使用和相同的代码

3) 使用.NET 2.0和C#2.0:使用和匿名方法:

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。)

LINQBridge将与VS2005一起使用,但您没有扩展方法、lambda表达式、查询表达式等。显然,迁移到C#3是一个更好的选择,但我更喜欢使用LINQBridge而不是自己实现相同的功能


如果需要同时获取最大值和最小值,所有这些建议都需要在列表中遍历两次。如果遇到从磁盘缓慢加载或类似情况,并且希望一次性计算多个聚合,您可能需要查看我的代码。(这也适用于.NET 2.0。)

是的,您应该使用委托和匿名方法

有关示例,请参见

基本上,您需要实现类似的功能

下面是一个示例实现

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());               
    }
}
公共类的东西
{
公共情报;
公共事业;
公共日期时间;
公共事物(int theInt,char theChar,DateTime theDateTime)
{
this.theInt=theInt;
this.theChar=theChar;
this.theDateTime=日期时间;
}
公共字符串转储()
{
返回string.Format(“I:{0},S:{1},D:{2}”,
时间);
}
}
公共类ThingCollection:列表
{
公共委托事物聚合函数(事物最佳,
事物(候选者);
公共事物聚合(事物种子,聚合函数Func)
{
事物=种子;
foreach(此处为t)
{
res=Func(res,t);
}
返回res;
}
}
类主类
{
公共静态void Main(字符串[]args)
{
事物a=新事物(1,'z',DateTime.Now);
thingb=新事物(2,'y',DateTime.Now.AddDays(1));
thingc=新事物(3,'x',DateTime.Now.AddDays(-1));
thingd=新事物(4,'w',DateTime.Now.AddDays(2));
thinge=新事物(5,'v',DateTime.Now.AddDays(-2));
ThingCollection tc=新ThingCollection();
tc.AddRange(新事物[{a,b,c,d,e});
事物结果;
//按日期列出的最大值
结果=总胆固醇(总胆固醇[0],
代表(最好的,候选的)
{ 
返回(Candidate.theDateTime.CompareTo(
最佳。日期时间)>0)?
候选人:
最好的;
}
);
WriteLine(“Max by date:{0}”,result.Dump());
//最小字符数
结果=总胆固醇(总胆固醇[0],
代表(最好的,候选的)
{ 
return(Candidate.theChar
结果是:

最大日期: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

结论:对于.NET2.0(使用VisualStudio2005),没有更好的方法

你似乎误解了答案(尤其是乔恩的)。你可以使用他的答案中的选项3。如果您不想使用LinqBridge,您仍然可以使用委托并自己实现
Max
方法,类似于我发布的方法:

delegate Decimal PropertyValue(IThing thing);

public class ThingList : IList<IThing> {
    public Decimal Max(PropertyValue prop) {
        Decimal result = Decimal.MinValue;
        foreach (IThing thing in this) {
            result = Math.Max(result, prop(thing));
        }
        return result;
    }
}
对于C#2.0和.Net 2.0,您可以对Max执行以下操作:

public delegate Decimal GetProperty<TElement>(TElement element);

public static Decimal Max<TElement>(IEnumerable<TElement> enumeration, 
                                    GetProperty<TElement> getProperty)
{
    Decimal max = Decimal.MinValue;

    foreach (TElement element in enumeration)
    {
        Decimal propertyValue = getProperty(element);
        max = Math.Max(max, propertyValue);
    }

    return max;
}
下面是使用C#3.0、.Net 3.5和Linq,在没有上述功能的情况下如何实现这一点:

string[] array = new string[] {"s","sss","ddsddd","333","44432333"};
array.Max( e => e.Length);
这里有一个尝试,使用C#2.0,在Skilwz的想法

public delegate T GetPropertyValueDelegate<T>(IThing t);

public T GetMaximum<T>(GetPropertyValueDelegate<T> getter)
    where T : IComparable
{
    if (this.Count == 0) return default(T);

    T max = getter(this[0]);
    for (int i = 1; i < this.Count; i++)
    {
        T ti = getter(this[i]);
        if (max.CompareTo(ti) < 0) max = ti;
    }
    return max;
}

一个通用的.NET2解决方案怎么样

public delegate A AggregateAction<A, B>( A prevResult, B currentElement );

public static Tagg Aggregate<Tcoll, Tagg>( 
    IEnumerable<Tcoll> source, Tagg seed, AggregateAction<Tagg, Tcoll> func )
{
    Tagg result = seed;

    foreach ( Tcoll element in source ) 
        result = func( result, element );

    return result;
}

//this makes max easy
public static int Max( IEnumerable<int> source )
{
    return Aggregate<int,int>( source, 0, 
        delegate( int prev, int curr ) { return curr > prev ? curr : prev; } );
}

//but you could also do sum
public static int Sum( IEnumerable<int> source )
{
    return Aggregate<int,int>( source, 0, 
        delegate( int prev, int curr ) { return curr + prev; } );
}
public委托一个AggregateAction(一个prevResult,一个currentElement);
公共静态标记聚合(
IEnumerable源、标记种子、聚合函数)
{
Tagg结果=种子;
foreach(源中的Tcoll元素)
结果=func(结果,元素);
返回结果;
}
//这让max很容易
公共静态int Max(IEnumerable源)
{
返回聚合(源,0,
委托(intprev,intcurr){return curr>prev?curr:prev;});
}
//但你也可以做加法
公共静态整数和(IEnumerable源)
{
返回聚合(源,0,
委托(int-prev,int-curr){return curr+p
string[] array = new string[] {"s","sss","ddsddd","333","44432333"};

Max(array, delegate(string e) { return e.Length;});
string[] array = new string[] {"s","sss","ddsddd","333","44432333"};
array.Max( e => e.Length);
public delegate T GetPropertyValueDelegate<T>(IThing t);

public T GetMaximum<T>(GetPropertyValueDelegate<T> getter)
    where T : IComparable
{
    if (this.Count == 0) return default(T);

    T max = getter(this[0]);
    for (int i = 1; i < this.Count; i++)
    {
        T ti = getter(this[i]);
        if (max.CompareTo(ti) < 0) max = ti;
    }
    return max;
}
ThingList list;
Decimal maxWeight = list.GetMaximum(delegate(IThing t) { return t.Weight; });
public delegate A AggregateAction<A, B>( A prevResult, B currentElement );

public static Tagg Aggregate<Tcoll, Tagg>( 
    IEnumerable<Tcoll> source, Tagg seed, AggregateAction<Tagg, Tcoll> func )
{
    Tagg result = seed;

    foreach ( Tcoll element in source ) 
        result = func( result, element );

    return result;
}

//this makes max easy
public static int Max( IEnumerable<int> source )
{
    return Aggregate<int,int>( source, 0, 
        delegate( int prev, int curr ) { return curr > prev ? curr : prev; } );
}

//but you could also do sum
public static int Sum( IEnumerable<int> source )
{
    return Aggregate<int,int>( source, 0, 
        delegate( int prev, int curr ) { return curr + prev; } );
}