我想汇总存储在List<>
中的记录。
如果我得到List<int>
,解决方案就是
var results = list.GroupBy(x => x).Select(g => g.Sum());
如果我得到List<MyObject>
public class MyObject
{
public MyObject(int pvalue)
{
Value = pvalue;
}
public int Value {get; set;}
public override bool Equals(object obj)
{
var p = obj as MyObject;
if (p == null)
return false;
return Value.Equals(p.Value);
}
public bool Equals(MyObject p)
{
if (p == null)
return false;
return Value.Equals(p.Value)
}
public override int GetHashCode()
{
int hash = 13;
hash = (hash * 7) + Value.GetHashCode();
return hash;
}
}
然后解决方案是:
myOjectList.GroupBy(x => x.Value).Select(g => new MyObject{ Value = g.Sum()});
现在,在我得到List<IMyObject>
,IMyObject
作为接口(或抽象类)的情况下,其具体实现得到了特定的属性(下面的示例类),我该如何解决多态性在之前的Linq声明的Select
中?
public interface IMyObject
{
int Value {get; set;}
bool Equals(object obj);
int GetHashCode();
}
public class MyObject1 : IMyObject
{
public MyObject1(int pvalue, string pname)
{
Value = pvalue;
Name = pname;
}
public int Value {get; set;}
public string Name { get; set; }
public override bool Equals(object obj)
{
var p = obj as MyObject1;
if (p == null)
return false;
return Name.Equals(p.Name) && Value.Equals(p.Value);
}
public bool Equals(MyObject1 p)
{
if (p == null)
return false;
return Name.Equals(p.Name) && Value.Equals(p.Value)
}
public override int GetHashCode()
{
int hash = 13;
hash += (hash * 7) + Value.GetHashCode();
hash += (hash * 7) + Name.GetHashCode();
return hash;
}
}
public class MyObject2 : IMyObject
{
public MyObject2(int pvalue, int pvalue2)
{
Value = pvalue;
Value2 = pvalue2;
}
public int Value {get; set;}
public string Value2 { get; set; }
public override bool Equals(object obj)
{
var p = obj as MyObject1;
if (p == null)
return false;
return Value2.Equals(p.Value2) && Value.Equals(p.Value);
}
public bool Equals(MyObject1 p)
{
if (p == null)
return false;
return Value2.Equals(p.Value2) && Value.Equals(p.Value)
}
public override int GetHashCode()
{
int hash = 13;
hash += (hash * 7) + Value.GetHashCode();
hash += (hash * 7) + Value2.GetHashCode();
return hash;
}
}
答案 0 :(得分:1)
FIRST SOLUTION: REFLECTION
myListOfIMyObjects
.GroupBy(x => x.GetType())
.Select(x =>
{
var constr = x.Key.GetConstructor(Type.EmptyTypes);
var instance = (IMyObject)constr.Invoke(new object[0]);
instance.Value = x.Select(o => o.Value).Sum();
return instance;
})
.ToList();
Pro: you can embed all in a single Select
, valid for all types implementing IMyObject
, and you don't have to modify it if you add other classes like MyObject3
or MyObject4
later.
Con: Reflection is a fragile pattern, because you cannot rely on compilation checks. Also, all the MyObject
classes must expose a parameterless constructor, and if it is not so, you will see an error only at runtime.
SECOND SOLUTION: OfType
var result1 = myListOfIMyObjects.OfType<MyObject1>();
var o1 = new MyObject1 { Value = result1.Sum(x => x.Value) };
var result2 = myListOfIMyObjects.OfType<MyObject2>();
var o2 = new MyObject2 { Value = result2.Sum(x => x.Value) };
var result = new List<IMyObject> { o1, o2 };
Pro: you have the compile-time checks, and the classes implementing IMyObject
can have different constructors with different parameters.
Con: It's more verbose (you cannot embed that code in a single Select
!), and if you add later other MyObject3
, MyObject4
in your domain, you have to come back here and add other rows manually.
答案 1 :(得分:1)
向IMyObject
添加新操作到Clone
对象:
public interface IMyObject {
int Value { get; set; }
bool Equals(object obj);
int GetHashCode();
IMyObject Clone();
}
实施Clone
方法:
public class MyObject1 : IMyObject {
...
public IMyObject Clone() {
return (IMyObject)this.MemberwiseClone();
}
}
public class MyObject2 : IMyObject {
...
public IMyObject Clone() {
return (IMyObject)this.MemberwiseClone();
}
}
现在您可以使用Clone
方法创建要返回的对象(注意:您没有说明如何为其他属性选择正确的值,因此我随意使用每个组中的第一个对象作为源)。
var ans = myObjectList.GroupBy(x => x.Value).Select(g => { var rtnval = g.First().Clone(); rtnval.Value = g.Sum(m => m.Value); return rtnval; });