Get unique objects From List of Objects - c#

I have class object like this:
public class SD
{
public string s { get; set; }
}
public class Obj
{
public string p { get; set; }
public string u { get; set; }
public List<SD> sD { get; set; }
}
public class ObjAssignStudy
{
public List<Obj> obj { get; set; }
}
And I get that data in this way:
{
"obj":[
{"p":"1","usertype":"A","studyData":[{"study":"1"},{"study":"2"}]},
{"p":"2","usertype":"A","studyData":[{"study":"1"}]}
{"p":"1","usertype":"A","studyData":[{"study":"2"},{"study":"3"}]}
]
}
What i want is, I want to get distinct P and append coresponding s to it ie. I want final object to contain data like this:
{
"obj":[
{"p":"1","usertype":"A","studyData":[{"study":"1"},{"study":"2"},{"study":"3"}]},
{"p":"2","usertype":"A","studyData":[{"study":"1"}]}
]
}
Any way by which I can achieve this in c# or linq?

var objs = new List<Obj>(){
new Obj
{
p = "1",
u = "A",
sD = new List<SD>() {new SD() { s = "1"}, new SD() { s = "2"}}
},
new Obj
{
p = "2",
u = "A",
sD = new List<SD>() {new SD() { s = "1"}}
},
new Obj
{
p = "1",
u = "A",
sD = new List<SD>() {new SD() { s = "2"}, new SD() { s = "3"}}
}
};
var distinct = from obj in objs
group obj by new { obj.p } into g
select new Obj {
p = g.Key.p,
u = g.First().u,
sD = g.SelectMany(i => i.sD).Distinct().ToList()
};
Modify class SD to use Distinct
public class SD
{
public string s { get; set; }
public override bool Equals(object obj)
{
return string.Equals(s, (obj as SD).s);
}
public override int GetHashCode()
{
return s.GetHashCode();
}
}

In this particular scenario you can use indexer to take particular List<SD> corresponding to the value you are passing to the object please go through the code that will explain it in detail;
Creation of Indexer
public List<SD> this[string index]
{
get
{
foreach (Obj item in ListObj)
{
if (item.p == index)
return item.sD;
}
return new List<SD>();
}
}
In the main function you can access the indexer and store Collect the details as the follows:
static void Main(string[] args)
{
ObjAssignStudy newInstance = new ObjAssignStudy();
List<SD> sampleData=newInstance["b"];// Gives the output
//collection as : EmptyList1,EmptyList2
}
Complete Code for your reference is here:
class Program
{
static void Main(string[] args)
{
ObjAssignStudy newInstance = new ObjAssignStudy();
List<SD> sampleData=newInstance["c"];
}
public class SD
{
public string s { get; set; }
}
public class Obj
{
public string p { get; set; }
public string u { get; set; }
public List<SD> sD { get; set; }
}
public class ObjAssignStudy
{
private List<Obj> _ListObj= new List<Obj>();
internal List<Obj> ListObj
{
get { return _ListObj; }
set { _ListObj = value; }
}
List<SD> tempList = new List<SD>();
public ObjAssignStudy()
{
tempList.Add(new SD() { s = "EmptyList1" });
ListObj.Add(new Obj() { p = "a", sD = tempList, u = "B" });
tempList.Add(new SD() { s = "EmptyList2" });
ListObj.Add(new Obj() { p = "b", sD =tempList, u = "C" });
tempList.Add(new SD() { s = "EmptyList3" });
ListObj.Add(new Obj() { p = "c", sD =tempList, u = "D" });
}
public List<SD> this[string index]
{
get
{
foreach (Obj item in ListObj)
{
if (item.p == index)
return item.sD;
}
return new List<SD>();
}
}
}
}
Test Cases:
List sampleData=newInstance["a"];// Gives the output
EmptyList1
List<SD> sampleData=newInstance["a"];// Gives the output
EmptyList1
EmptyList2
List<SD> sampleData=newInstance["a"];// Gives the output
EmptyList1
EmptyList2
EmptyList3

Related

Populate a list in constructor

I'm looking for the better way to initialize a list directly in the constructor of my object. The goal is to put the initialize code at the same place, without taking several many lines.
public class Object1
{
public string data1 { get; set; }
public string data2 { get; set; }
public List<Object2> myList { get; set; }
}
public class Object2
{
public int Id { get; set; }
public string myData { get; set; }
}
public class Object3
{
public int Id { get; set; }
public string myOtherData { get; set; }
}
There is my way in order to initialize myList from Objet1 :
public static void myProgram()
{
List<Object3> test = new List<Object3>
{
new Object3
{
Id = 1,
myOtherData = "blabla"
},
new Object3
{
Id = 8,
myOtherData = "blabla"
}
};
/* That is what I do now */
Object1 myObject = new Object1
{
data1 = "toto",
data2 = "titi",
myList = test != null && test.Count > 0 ? new List<Object2>() : null
};
foreach (Object3 obj3 in test)
{
if (obj3.Id > 3)
{
myObject.myList.Add(new Object2
{
Id = obj3.Id,
myData = $"lol {obj3.myOtherData}"
});
}
}
}
I'm looking for a way which avoid to use a foreach after construction of my object. Something like this :
/* That is what I try to do */
Object1 myObject = new Object1
{
data1 = "toto",
data2 = "titi",
myList = test != null && test.Count > 0 ? new List<Object2>().AddRange( /* PUT THE FOREACH HERE */)
}
I think we can use lambda / delegates in order to create anonymous function which will fill the list, but I don't how it works.
}
You can do it with Linq.
myList = test?.Where(x => x.Id > 3).Select(x => new Object2
{
Id = x.Id,
myData = $"lol {x.myOtherData}"
}).ToList()

Converting table in tree

Is there any scope for improvement in my program which converts flat db entity to a tree data structure.
I don't want to loose the Generic flexibility as i should be able to use the same method for any other DBEntity class
Interface for db entity class
public interface IDbEntityNode
{
int Id { get; set; }
int ParentId { get; set; }
}
Example of db Entity class
public class ExceptionCategory :IDbEntityNode
{
public int Id { get; set; }
public int ParentId { get; set; }
public string Data { get; set; }
public ExceptionCategory(string data, int id, int parentId)
{
Id = id;
ParentId = parentId;
Data = data;
}
}
Generic class which holds the structure of tree node
public class GenericNode<T>
{
public T NodeInformation { get; set; }
public GenericNode<T> Parent { get; set; }
public List<GenericNode<T>> Children { get; set; } = new List<GenericNode<T>>();
}
Method which coverts flat list to tree
public static List<GenericNode<T>> CreateGenericTree<T>(List<T> flatDataObject,Func<T,bool> IsRootNode) where T : IDbEntityNode
{
var lookup = new Dictionary<int, GenericNode<T>>();
var rootNodes = new List<GenericNode<T>>();
var noOfElements = flatDataObject.Count;
for (int element = 0; element < noOfElements; element++)
{
GenericNode<T> currentNode;
if (lookup.TryGetValue(flatDataObject[element].Id, out currentNode))
{
currentNode.NodeInformation = flatDataObject[element];
}
else
{
currentNode = new GenericNode<T>() { NodeInformation = flatDataObject[element] };
lookup.Add(flatDataObject[element].Id, currentNode);
}
if (IsRootNode(flatDataObject[element]))
{
rootNodes.Add(currentNode);
}
else
{
GenericNode<T> parentNode;
if (!lookup.TryGetValue(flatDataObject[element].ParentId, out parentNode))
{
parentNode = new GenericNode<T>();
lookup.Add(flatDataObject[element].ParentId, parentNode);
}
parentNode.Children.Add(currentNode);
currentNode.Parent = parentNode;
}
}
return rootNodes;
}
Execution:
private static void Main(string[] args)
{
List<IDbEntityNode> flatDataStructure = new List<IDbEntityNode>
{
new ExceptionCategory("System Exception",1,0),
new ExceptionCategory("Index out of range",2,1),
new ExceptionCategory("Null Reference",3,1),
new ExceptionCategory("Invalid Cast",4,1),
new ExceptionCategory("OOM",5,1),
new ExceptionCategory("Argument Exception",6,1),
new ExceptionCategory("Argument Out Of Range",7,6),
new ExceptionCategory("Argument Null",8,6),
new ExceptionCategory("External Exception",9,1),
new ExceptionCategory("Com",10,9),
new ExceptionCategory("SEH",11,9),
new ExceptionCategory("Arithmatic Exception",12,1),
new ExceptionCategory("DivideBy0",13,12),
new ExceptionCategory("Overflow",14,12),
};
var tree = CreateGenericTree(flatDataStructure, IsRootNode);
}
private static bool IsRootNode(IDbEntityNode dbEntity)
{
bool isRootNode = false;
if (dbEntity.ParentId == 0 )
isRootNode = true;
return isRootNode;
}
Created a generic approach, table objects need to follow the dbSet interface and TreeNode objects need to follow the ITreeNode. I used binarySerach to make this as fast as possible. No recursion needed. The logic ensures that you do not need to have the items in a particular order. I did not throw an error when out of the loop when there are still unassigned objects, this can be easy added.
using System.Collections.Generic;
public interface ITreeNode
{
string ParentId { get; set; }
string Id { get; set; }
dbItem item { get; set; }
List<ITreeNode> Nodes { get; set; }
}
public class TreeNode : ITreeNode
{
public TreeNode()
{ }
public string ParentId { get; set; }
public string Id { get; set; }
public dbItem item { get; set; }
public List<ITreeNode> Nodes { get; set; }
}
public class dbItem
{
public string ParentId { get; set; }
public string Id { get; set; }
public string Name { get; set; }
}
class app
{
static void Main()
{
List<dbItem> dbSet = new List<dbItem>();
dbSet.Add(new dbItem() { Id = "5", ParentId = "1", Name = "Jan" });
dbSet.Add(new dbItem() { Id = "25", ParentId = "1", Name = "Maria" });
dbSet.Add(new dbItem() { Id = "1", Name = "John" });
dbSet.Add(new dbItem() { Id = "8", ParentId = "2", Name = "Cornelis" });
dbSet.Add(new dbItem() { Id = "2", Name = "Ilse" });
dbSet.Add(new dbItem() { Id = "3", Name = "Nick" });
dbSet.Add(new dbItem() { Id = "87", ParentId = "5", Name = "Rianne" });
dbSet.Add(new dbItem() { Id = "67", ParentId = "3000", Name = "Rianne" });
dbSet.Add(new dbItem() { Id = "3000", Name = "Max" });
List<TreeNode> result = BuildTree<TreeNode>(dbSet);
}
private class ParentComparer<T> : IComparer<ITreeNode> where T: ITreeNode
{
public int Compare(ITreeNode x, ITreeNode y)
{
if (x.ParentId == null) return -1; //have the parents first
return x.ParentId.CompareTo(y.ParentId);
}
}
private class IdComparer<T> : IComparer<ITreeNode> where T : ITreeNode
{
public int Compare(ITreeNode x, ITreeNode y)
{
return x.Id.CompareTo(y.Id);
}
}
static private List<T> BuildTree<T> (List<dbItem> table) where T: ITreeNode, new()
{
//temporary list of tree nodes to build the tree
List<T> tmpNotAssignedNodes = new List<T>();
List<T> tmpIdNodes = new List<T>();
List<T> roots = new List<T>();
IComparer<T> pc = (IComparer<T>) new ParentComparer<T>();
IComparer<T> ic = (IComparer<T>) new IdComparer<T>();
foreach (dbItem item in table)
{
T newNode = new T() { Id = item.Id, ParentId = item.ParentId, item = item };
newNode.Nodes = new List<ITreeNode>();
T dummySearchNode = new T() { Id = item.ParentId, ParentId = item.ParentId };
if (string.IsNullOrEmpty(item.ParentId))
roots.Add(newNode);
else
{
int parentIndex = tmpIdNodes.BinarySearch(dummySearchNode, ic);//Get the parent
if (parentIndex >=0)
{
T parent = tmpIdNodes[parentIndex];
parent.Nodes.Add(newNode);
}
else
{
parentIndex = tmpNotAssignedNodes.BinarySearch(dummySearchNode, pc);
if (parentIndex < 0) parentIndex = ~parentIndex;
tmpNotAssignedNodes.Insert(parentIndex, newNode);
}
}
dummySearchNode.ParentId = newNode.Id;
//Cleanup Unassigned
int unAssignedChildIndex = tmpNotAssignedNodes.BinarySearch(dummySearchNode, pc);
while (unAssignedChildIndex >= 0 && unAssignedChildIndex < tmpNotAssignedNodes.Count)
{
if (dummySearchNode.ParentId == tmpNotAssignedNodes[unAssignedChildIndex].ParentId)
{
T child = tmpNotAssignedNodes[unAssignedChildIndex];
newNode.Nodes.Add(child);
tmpNotAssignedNodes.RemoveAt(unAssignedChildIndex);
}
else unAssignedChildIndex--;
}
int index = tmpIdNodes.BinarySearch(newNode, ic);
tmpIdNodes.Insert(~index, newNode);
}
return roots;
}
}
Try following solution using recursive code :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
public static List<IDbEntityNode> flatDataStructure = null;
public static Dictionary<int?, List<IDbEntityNode>> dict = null;
static void Main(string[] args)
{
flatDataStructure = new List<IDbEntityNode>
{
new ExceptionCategory("System Exception",1,0),
new ExceptionCategory("Index out of range",2,1),
new ExceptionCategory("Null Reference",3,1),
new ExceptionCategory("Invalid Cast",4,1),
new ExceptionCategory("OOM",5,1),
new ExceptionCategory("Argument Exception",6,1),
new ExceptionCategory("Argument Out Of Range",7,6),
new ExceptionCategory("Argument Null",8,6),
new ExceptionCategory("External Exception",9,1),
new ExceptionCategory("Com",10,9),
new ExceptionCategory("SEH",11,9),
new ExceptionCategory("Arithmatic Exception",12,1),
new ExceptionCategory("DivideBy0",13,12),
new ExceptionCategory("Overflow",14,12),
};
dict = flatDataStructure.GroupBy(x => x.ParentId, y => y)
.ToDictionary(x => x.Key, y => y.ToList());
GenericNode<IDbEntityNode> root = new GenericNode<IDbEntityNode>();
root.Parent = null;
int rootId = 0;
root.NodeInformation.Id = rootId;
root.NodeInformation.name = "root";
root.NodeInformation.ParentId = null;
CreateGenericTree(root);
}
public static void CreateGenericTree<T>(GenericNode<T> parent) where T : IDbEntityNode, new()
{
if (dict.ContainsKey(parent.NodeInformation.Id))
{
List<IDbEntityNode> children = dict[parent.NodeInformation.Id];
foreach (IDbEntityNode child in children)
{
GenericNode<T> newChild = new GenericNode<T>();
if (parent.Children == null) parent.Children = new List<GenericNode<T>>();
parent.Children.Add(newChild);
newChild.NodeInformation.Id = child.Id;
newChild.NodeInformation.ParentId = parent.NodeInformation.Id;
newChild.NodeInformation.name = child.name;
newChild.Parent = parent;
CreateGenericTree(newChild);
}
}
}
}
public class GenericNode<T> where T : new()
{
public T NodeInformation = new T();
public GenericNode<T> Parent { get; set; }
public List<GenericNode<T>> Children { get; set; }
}
public class IDbEntityNode
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string name { get; set; }
}
public class ExceptionCategory : IDbEntityNode
{
public string Data { get; set; }
public ExceptionCategory(string data, int id, int parentId)
{
Id = id;
ParentId = parentId;
Data = data;
}
}
}

C# printing LINQ-table to console without specifying the properties

I would like to make a method to print a LINQ (table) with all its properties and values to the console.
I'm currently trying to do this via the System.Reflection.GetType().GetProperties()
What I think is going wrong is the type of parameter I try to send to the method. If possible this should be a var so I can use this method with any class list. (not sure if this is possible)
The issue is with the printtabel() method.
I started from:
Print a table with LINQ
namespace LINQ
{
class Program
{
public class Bier
{
public int BierNr { get; set; }
public string Biernaam { get; set; }
public float Alcohol { get; set; }
public Brouwer Brouwer { get; set; } //associatie met een brouwer
public override string ToString() { return Biernaam + ": " + Alcohol + "% alcohol"; }
}
public class Brouwer
{
public int BrouwerNr { get; set; }
public string Brouwernaam { get; set; }
public bool Belgisch { get; set; }
public List<Bier> Bieren { get; set; }
public override string ToString() { return "Brouwerij " + Brouwernaam + " (" + (Belgisch ? "Belgisch" : "Niet Belgisch") + ")"; }
}
public class Brouwers
{
public List<Brouwer> GetBrouwers()
{
List<Brouwer> lijst = new List<Brouwer>();
Brouwer palm = new Brouwer { BrouwerNr = 1, Brouwernaam = "Palm", Belgisch = true };
palm.Bieren = new List<Bier> {
new Bier {BierNr=1,Biernaam="Palm Dobbel", Alcohol=6.2F, Brouwer=palm},
new Bier {BierNr=2, Biernaam="Palm Green", Alcohol=0.1F, Brouwer=palm},
new Bier {BierNr=3, Biernaam="Palm Royale", Alcohol=7.5F, Brouwer=palm}
};
lijst.Add(palm);
Brouwer hertogJan = new Brouwer { BrouwerNr = 2, Brouwernaam = "Hertog Jan", Belgisch = false };
hertogJan.Bieren = new List<Bier> {
new Bier{ BierNr=4, Biernaam="Hertog Jan Dubbel", Alcohol=7.0F, Brouwer=hertogJan},
new Bier{ BierNr=5, Biernaam="Hertog Jan Grand Prestige", Alcohol=10.0F, Brouwer=hertogJan} };
lijst.Add(hertogJan);
Brouwer inBev = new Brouwer { BrouwerNr = 3, Brouwernaam = "InBev", Belgisch = true };
inBev.Bieren = new List<Bier> {
new Bier { BierNr=6, Biernaam="Belle-vue kriek L.A", Alcohol=1.2F, Brouwer=inBev},
new Bier { BierNr=7, Biernaam="Belle-vue kriek", Alcohol=5.2F, Brouwer=inBev},
new Bier { BierNr=8, Biernaam="Leffe Radieuse", Alcohol=8.2F,Brouwer=inBev},
new Bier { BierNr=9, Biernaam="Leffe Triple", Alcohol=8.5F,Brouwer=inBev} };
lijst.Add(inBev);
//return new List<Brouwer> { palm, hertogJan, inBev };
return lijst;
}
}
static void Main(string[] args)
{
var brouwers = new Brouwers().GetBrouwers();
var belgischeBrouwerijenMet3Bieren =
from brouwer in brouwers
where brouwer.Belgisch && brouwer.Bieren.Count == 3
select brouwer;
foreach (var brouwer in belgischeBrouwerijenMet3Bieren)
Console.WriteLine(brouwer.Brouwernaam);
var bieren = from brouwer in brouwers
from bier in brouwer.Bieren
select bier;
string vorigeBrouwer = "";
foreach (var bier in bieren)
{
if (bier.Brouwer.ToString() != vorigeBrouwer)
{
Console.WriteLine(bier.Brouwer);
vorigeBrouwer = bier.Brouwer.ToString();
}
Console.WriteLine($"\t {bier.ToString()}");
}
Console.WriteLine(printtabel(belgischeBrouwerijenMet3Bieren));
Console.ReadLine();
}
public string printtabel(IEnumerable<Brouwer> response)
{
StringBuilder sb = new StringBuilder();
foreach (PropertyInfo prop in response.GetType().GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
object value = prop.GetValue(response, new object[] { });
sb.AppendLine($"{prop.Name} = {value}");
}
return sb.ToString();
}
}
}
Error CS0120 An object reference is required for the non-static field, method, or property 'Program.printtabel(IEnumerable)' LINQ 204 Active
You can fix it by writing:
public static string printtabel(IEnumerable<Brouwer> response)
You are calling a non static method from a static method. Set printtabel static and this error should disappear.

Group items by content of list

Lets say i got a something like this:
public class Subscriber{
public string Name {get; set;}
}
public class SomeData{
public string Content {get; set;}
}
public class InputData {
public Subscriber Subscribers { get; set; }
public IEnumerable<SomeData> DataItems { get; set; }
}
public class QueueItem {
public IEnumerable<Subscriber> Subscribers { get; set; }
public IEnumerable<SomeData> DataItems { get; set; }
}
Now lets say i get a List<InputData> full of "Subscribers" with a list of data for each subscriber.
Now i want to compare the list of data of each subscriber, and end up with a List<QueueItem>, where if 2 subscribers have the same set of data items, they would be 1 QueueItem.
Hope this makes sense
The technique is using EqualityComparer with Enumerable.SequenceEqual()
public class Subscriber
{
public string Name { get; set; }
// For compare
public override bool Equals(object obj) { return string.Equals(this.Name, ((Subscriber)obj).Name); }
public override int GetHashCode() { return this.Name.GetHashCode(); }
}
public class SomeData
{
public string Content { get; set; }
// For compare
public override bool Equals(object obj) { return string.Equals(this.Content, ((SomeData)obj).Content); }
public override int GetHashCode() { return this.Content.GetHashCode(); }
}
public class InputData
{
public Subscriber Subscribers { get; set; }
public IEnumerable<SomeData> DataItems { get; set; }
// Should always initialize an empty collection
public InputData() { this.DataItems = new List<SomeData>(); }
}
public class QueueItem
{
public IEnumerable<Subscriber> Subscribers { get; set; }
public IEnumerable<SomeData> DataItems { get; set; }
// Should always initialize an empty collection
public QueueItem() { this.Subscribers = new List<Subscriber>(); this.DataItems = new List<SomeData>(); }
}
public class DataItemsEqualityComparer : EqualityComparer<IEnumerable<SomeData>>
{
public override bool Equals(IEnumerable<SomeData> x, IEnumerable<SomeData> y)
{
return Enumerable.SequenceEqual(x.OrderBy(i => i.Content), y.OrderBy(i => i.Content));
}
public override int GetHashCode(IEnumerable<SomeData> obj)
{
return obj.Select(i => i.GetHashCode()).Sum().GetHashCode();
}
}
Usage
var data = new List<InputData>();
var fruits = new[] { new SomeData() { Content = "apple" }, new SomeData() { Content = "pear"} };
var colors = new[] { new SomeData() { Content = "red" }, new SomeData() { Content = "blue" }, new SomeData() { Content = "green" } };
data.Add(new InputData() { Subscribers = new Subscriber() { Name = "Alice" }, DataItems = new List<SomeData>(fruits) });
data.Add(new InputData() { Subscribers = new Subscriber() { Name = "Bob" }, DataItems = new List<SomeData>(colors) });
data.Add(new InputData() { Subscribers = new Subscriber() { Name = "Charlie" }, DataItems = new List<SomeData>(fruits) });
List<QueueItem> groupedData = data.GroupBy(
i => i.DataItems,
i => i.Subscribers,
new DataItemsEqualityComparer())
.Select(i => new QueueItem() { Subscribers = i, DataItems = i.Key }).ToList();
Result
QueueItem :
Subscribers:
- Alice
- Charlie
Data:
- apple
- pear
QueueItem :
Subscribers:
- Bob
Data:
- red
- blue
- green
var queue = Dictionary(Subscriber, List<SomeData>);
//And lets just for example add some data
var items1 = new List<SomeData>();
items1.Add(new SomeData("test"));
items1.Add(new SomeData("test2"));
var items2 = new List<SomeData>();
items2.Add(new SomeData("test"));
queue.Add(new Subscriber("Peter"), items1);
queue.Add(new Subscriber("Luke"), items1);
queue.Add(new Subscriber("Anna"), items2);
Dictionary<Subscriber, List<SomeData>> myDictionary = queue
.GroupBy(o => o.PropertyName)
.ToDictionary(g => g.Key, g => g.ToList());

How do you specify the order of columns of a doddlereport without creating a new object

I am trying to utilize CustomAttributes to specify the order of the properties of the object
public class WCG : DistrictExport
{
[DataMember(Name = "Survey", Order = 190)]
public string Survey { get; set; }
[DataMember(Name = "Western Hemisphere\nwith Europe", Order = 200)]
public string WesternHemisphereWithEurope { get; set; }
[DataMember(Name = "Eastern Hemisphere", Order = 210)]
public string EasternHemisphere { get; set; }
}
How do you specify the order of columns of a doddlereport without creating a new object?
List<object> report = GetReportResults();
report = new Report(results.ToReportSource(), Writer);
OK!,I try your problem.And I'm great worked.Try my source:
My simple Test class:
public class Test
{
[DataMember(Name = "A", Order = 96)]
public string A { get; set; }
[DataMember(Name = "B", Order = 97)]
public string B { get; set; }
[DataMember(Name = "C", Order = 98)]
public string C { get; set; }
}
And Ext:
public static class Ext
{
public static IList<KeyValuePair<string, int>> AsOrderColumns<T>(this T t)
where T : class
{
return t.GetType()
.GetProperties()
.Where(w => w.IsOrderColumn())
.Select(s => s.GetOrderColumn())
.OrderBy(o => o.Value)
.ToList();
}
private static bool IsOrderColumn(this PropertyInfo prop)
{
return prop.GetCustomAttributes(typeof(DataMemberAttribute), true)
.Any();
}
private static KeyValuePair<string, int> GetOrderColumn(this PropertyInfo prop)
{
var attr = prop.GetCustomAttributes(typeof(DataMemberAttribute), true)
.ElementAt(0) as DataMemberAttribute;
return (attr != null)
? new KeyValuePair<string, int>(attr.Name, attr.Order)
: new KeyValuePair<string, int>();
}
public static IList<object> AsOrderRow<T>(this T t)
where T : class
{
return t.GetType()
.GetProperties()
.Where(w => w.IsOrderColumn())
.OrderBy(o => o.GetOrderColumn().Value)
.Select(s => s.GetValue(t, null))
.ToList();
}
}
Console test code:
class Program
{
static void Main(string[] args)
{
var test = new Test();
var tests = new List<Test>()
{
new Test() {A = "A-1.1", B = "B-1.2", C = "C-1.3"},
new Test() {A = "A-2.1", B = "B-2.2", C = "C-2.3"},
new Test() {A = "A-3.1", B = "B-3.2", C = "C-3.3"},
new Test() {A = "A-4.1", B = "B-4.2", C = "C-4.3"}
};
Console.WriteLine(String.Join<string>("\t", test.AsOrderColumns().Select(s => String.Format("{0}({1})", s.Key, s.Value))));
foreach (var item in tests)
{
Console.WriteLine(String.Join<object>("\t", item.AsOrderRow()));
}
Console.ReadKey();
}
}

Categories