I would like to generate some Items with IDs. Item is just a class with an ID integer attribute. They should get added to a list after creating them. So I have a class that manages all the items
internal static class ItemPool
{
public static readonly List<Item> items = new List<Item>(); // Store all the items here
public static Item CreateItem()
{
int itemId = items.Count; // Just take the next free slot index
Item itemToCreate = new Item(itemId);
items.Add(itemToCreate);
return itemToCreate;
}
public static void DestroyItem(int itemId)
{
activeItems.RemoveAt(itemId);
}
}
Now I can create some items
Item firstItem = ItemPool.CreateItem(); // generates item with ID 0
Item secondItem = ItemPool.CreateItem(); // generates item with ID 1
ItemPool.DestroyItem(firstItem.id); // Recudes the list count to 1
Item thirdItem = ItemPool.CreateItem(); // generates item with ID 1 - ERROR
The third item is not allowed to have the ID 1 because item 2 already has it.
When changing the code two questions come up:
How to manage the IDs for items in this list so that none of them have the same ID?
public static Item CreateItem()
{
int itemId = temporaryUniqueId; // create a temporary unique ID
// ... other code
}
What is a more optimized way than going for
public static void DestroyItem(int itemId)
{
activeItems = activeItems.Where(item => item.id != itemId).ToList();
}
I know I could do
public static void DestroyItem(Item item)
{
activeItems.Remove(item);
}
but I think removing by ID is more safe. I am asking this because for this case performance is everything.
The IDs don't have to be integer values
Since having an ID as an integer is not a requirement, one way to do this would be to use a GUID as a unique identifier to avoid having to deal with potential conflict.
public class Item
{
public Guid Id { get; }
public Item()
{
Id = Guid.NewGuid();
}
}
Then, your ItemPool class could be changed to use a ConcurrentDictionary (to avoid any race conditions):
internal sealed class ItemPool
{
private readonly ConcurrentDictionary<Guid, Item> items = new ConcurrentDictionary<Guid, Item>(); // Store all the items here
public Item CreateItem()
{
Item itemToCreate = new Item();
items.TryAdd(itemToCreate.Id, itemToCreate);
return itemToCreate;
}
public void DestroyItem(Guid itemId)
{
activeItems.TryRemove(itemId, out Item _);
}
}
I took the liberty of removing the static parameter of the class to make it easier to test. I also made the items field private for better encapsulation. You do not want anyone other class to bypass ItemPool and start manipulating the collection by themselves :)
Related
I'm using PRISM6.
In my Model I have simple:
public ObservableCollection<Id> Ids { get; }
In ViewModel I would like to return those items in public ObservableCollection<string> Ids
How can I convert it to string? At this moment I have:
private ObservableCollection<string> _ids = new ObservableCollection<string>();
public ObservableCollection<string> Ids {
get {
_ids.Add("Empty");
foreach (var item in _Model.Ids) {
_ids.Add(item.ToString());
}
return _ids;
}
}
But it does not work when I update my collection in Model.
My old version without convert works fine. public ObservableCollection<Id> Ids => _Model.Ids; I need it in string because somehow I need to add "Empty" to combobox. If ther is any better solution for it please tell me :)
I'm sure there are much better solutions out there, but here's one method I particularly like:
public class MainViewModel
{
// Source Id collection
public ObservableCollection<Id> Ids { get; }
// Empty Id collection
public ObservableCollection<Id> Empty { get; } = new ObservableCollection<Id>();
// Composite (combination of Source + Empty collection)
// View should bind to this instead of Ids
public CompositeCollection ViewIds { get; }
// Constructor
public MainViewModel(ObservableCollection<Id> ids)
{
ViewIds = new CompositeCollection();
ViewIds.Add(new CollectionContainer {Collection = Empty });
ViewIds.Add(new CollectionContainer {Collection = Ids = ids });
// Whenever something changes in Ids, Update the collections
CollectionChangedEventManager.AddHandler(Ids, delegate { UpdateEmptyCollection(); });
UpdateEmptyCollection(); // First time
}
private void UpdateEmptyCollection()
{
// If the source collection is empty, push an "Empty" id into the Empty colleciton
if (Ids.Count == 0)
Empty.Add(new Id("Empty"));
// Otherwise (has Ids), clear the Empty collection
else
Empty.Clear();
}
}
I have a dictionary for clustering purpose in a class named Cluster in C# as:
Dictionary<int, List<ClusterMember>>
whereas int represent the cluster id, List<ClusterMember>> represent the members in that cluster id and ClusterMember is another class. I have shown here the whole code structure as:
public class ClusterMember
{
public string _name { get; set; }
}
public class Cluster
{
public Dictionary<int, List<ClusterMember>> _dic { get; set; }
public Cluster(int _id, List<ClusterMember> _clusMem)
{
_dic.Add(_id, _clusMem);
}
}
whereas I have used these classes in this method as:
public static List<Cluster> DP_Cluster(List<string> _customer, double _alpha)
{
var _currentClusters = 0; // current number of clusters i.e. "k"
var _memberNumber = 0; // running member number i.e. "n"
//var _dic = new Dictionary<int, List<string>>();
var _probOld = 0.0;
var _probNew = 0.0;
List<Cluster> _myClusters = new List<Cluster>();
//Cluster _cluster = new Cluster(?);
// How to Add cluster using above classes
// How to Add cluster Member using above classes
_myClusters.Add(_cluster);
//_dic.Add(_currentClusters, _customer.ElementAt(_memberNumber));
_currentClusters += 1;
for(int _i = 1; _i < _customer.Count - 1; _i++)
{
if( _i <= _currentClusters)
{
_probOld = myClusters[_i].Members.Count / ((_i+1) - 1 + _alpha);
}
else
{
_probNew = _alpha / ((_i+1) - 1 + _alpha);
}
if(_probNew > _probOld)
{
// Add _customer.ElementAt(_memberNumber+=1) to New Cluster
Cluster cluster = new Cluster( _currentClusters += 1 );
myClusters.Add(cluster);
}
else
{
// Add _customer.ElementAt(_memberNumber+=1) to Old Cluster
}
}
return myClusters;
}
Now how do I Add in _dic object of Dictionary while in for loop? Moreover I may have to add more than one cluster members to same _id more than once as
I may add a cluster member to _id = 1 in an iteration,
then have to add a cluster member to an _id = 2 in another
iteration,
then it may turn to add another cluster member to same id i.e. _id = 1 and vice versa.
Moreover, it'll be more meaningful to me if it is possible to start cluster id with 1 (not 0as of default _dic index).
Moreover I may have to add more than one cluster members to same id
more than once
You can check for the key for each loop iteration like that:
public void AddInCluster(int id, List<ClusterMember> _clusMem)
{
if (_dic.ContainsKey(id))
{
foreach (var clusterMember in _clusMem)
{
_dic[id].Add(clusterMember);
}
}
else
{
_dic.Add(id, _clusMem);
}
}
Or you can use the TryGetValue from Dictionary:
public void AddInCluster(int id, List<ClusterMember> _clusMem)
{
List<ClusterMember> members;
if (_dic.TryGetValue(id, out members))
{
foreach (var clusterMember in _clusMem)
{
members.Add(clusterMember);
}
}
else
{
_dic.Add(id, _clusMem);
}
}
Moreover, it'll be more meaningful to me if it is possible to start
cluster id with 1
What about wrapping your int into a ClusterId class which could raise exception if an id is 0?
Also your Cluster class could override the accessor operator [] on the dictionary to give a meaningful abstraction in your context (starting from 1 instead of 0 for example)
You may also add a Get working like your Add to check if this id exists:
public List<ClusterMember> GetFromCluster(ClusterId id)
{
if (_dic.ContainsKey(id))
{
return _dic[id];
}
throw new ClusterDoesNotContainsThisId(id);
}
How about using the Add method for Dictionaries? like:
if(needToAddNewCluster){
_dic.Add(index, new List<ClusterMember>());
}
if(needToExtendCluster){
_dic[index].Add(clusMem);
}
in this i assume that needToAddNewCluster checks that _dic.ContainsKey(index).
You can add method to your Cluster class
public void AddToCluster(int id, ClusterMember member)
{
// checks if cluster with specific id is already in Dictionary
if(!_dic.ContainsKey(id))
_dic.Add(id,new List<ClusterMember>());
_dic[id].Add(member);
}
You can use it in iteration like this
int id = 1; // cluster id
foreach(var m in members)
{
// adding members to cluster with id = 1
cluster.AddToCluster(id,m);
}
UPDATE
also can we get list count for each cluster id i.e. cluster members count for each cluster id?
You can add these two methods
// get members count for specific cluster id
public int GetCount(int id)
{
return _dict[id].Count;
}
// get members count for all clusters
public Dictionary<int,int> GetCounts()
{
return _dict.ToDictionary(k=>k.Key,v=>v.Value.Count);
}
Which you can access like this
var counts = cluster.GetCounts();
var c1Cnt=counts[1]; // 1 is cluster id
I would change the implementation of the Culster class slightly. The _dic should be a getter only property with an initializer. According to the usual .NET C# naming conventions, properties should be in PascalCase, therefore I renamed it to Dic. (A better name would be MemberDictionary or Members). Underlined _camelCase identifiers are usually used for fields. Method parameters and local variables have camelCase.
Then add new methods for adding one or several members. Both methods first check to see whether the list is already there. If it's there new members are added to the list, otherwise a new list is created initialized with the new members and then added to the dictionary.
public class Cluster
{
public Dictionary<int, List<ClusterMember>> Dic { get; }
= new Dictionary<int, List<ClusterMember>>();
// Initialize empty cluster.
public Cluster()
{
}
// Initialize cluster with one initial member.
public Cluster(int key, ClusterMember member)
{
Add(key, member);
}
// Initialize cluster with many members.
public Cluster(int key, IEnumerable<ClusterMember> members)
{
Add(key, members);
}
// Allows you to a one new member.
public void Add(int key, ClusterMember member)
{
if (Dic.TryGetValue(key, out var memberList)) {
memberList.Add(member);
} else {
memberList = new List<ClusterMember> { member };
Dic.Add(key, memberList);
}
}
// Allows you to add many members.
public void Add(int key, IEnumerable<ClusterMember> members)
{
if (Dic.TryGetValue(key, out var memberList)) {
memberList.AddRange(members);
} else {
memberList = new List<ClusterMember>(members);
Dic.Add(key, memberList);
}
}
}
This implementation delegates the dictionary and list creation and the details of adding members to the Cluster class.
Btw.: Dictionaries work with a key, not an index.
I don't know where you are getting the member number from, nor do I understand your clustering algorithm; however, I think that with these changes DP_Cluster could look like this:
public static List<Cluster> DP_Cluster(List<string> customers, double alpha)
{
double probOld = 0.0;
double probNew = 0.0;
var clusters = new List<Cluster>();
Cluster currentCluster = null;
for (int i = 0; i < customers.Count; i++) {
if (i <= clusters.Count) {
probOld = clusters[i].Dic.Count / (i + alpha);
} else {
probNew = alpha / (i + alpha);
}
if (probNew > probOld || currentCluster == null) {
currentCluster = new Cluster();
clusters.Add(currentCluster);
}
currentCluster.Add(_memberNumber, new ClusterMember { Name = customers[i] });
}
return clusters;
}
Some of the constructors and methods in Cluster could prove superfluous eventually, as we are always adding one single customer at a time.
I'm doing something wrong because after the loop executed myData still contains objects with blank ids. Why isn't the myData object being updated in the following foreach loop, and how do I fix it?
I thought it could be that I wasn't passing the object by reference, but added a ref keyword and also moved to the main method and I'm still showing the object not being updated.
Additional Information
The user object in the foreach loop is being updated, but the myData list does not reflect the updates I see being applied to the user object.
** Solution **
I was not creating a List but an Enumerable which was pulling the json each time I went through myData in a foreach list. Adding a ToList() fixed my issue.
public class MyData
{
public string ID { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
int index = 0;
// Does not allow me to up, creates an IEnumerable
//IEnumerable<MyData> myData = JObject.Parse(json)["Users"]
// .Select(x => new MyData()
// {
// ID = x["id"].ToString(),
// Properties = x.OfType<JProperty>()
// .ToDictionary(y => y.Name, y => y.Value.ToString())
// });
//Works allows me to update the resulting list.
IEnumerable<MyData> myData = JObject.Parse(json)["Users"]
.Select(x => new MyData()
{
ID = x["id"].ToString(),
Properties = x.OfType<JProperty>()
.ToDictionary(y => y.Name, y => y.Value.ToString())
}).ToList();
foreach (var user in myData) // Also tried myData.ToList()
{
if (string.IsNullOrEmpty(user.ID))
{
user.ID = index.ToString();
user.Properties["id"] = index.ToString();
}
index++;
}
public class MyData
{
public MyData()
{
this.Properties = new Dictionary<string,string>();
}
public string ID { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
public static void Main(string[] args)
{
IEnumerable<MyData> myDataList = new List<MyData>();
int index = 0; // Assuming your starting point is 0
foreach (var obj in myDataList)
{
if (obj != null && string.IsNullOrEmpty(obj.ID))
{
obj.ID = index.ToString();
// Checks if the Properties dictionary has the key "id"
if (obj.Properties.ContainsKey("id"))
{
// If it does, then update it
obj.Properties["id"] = obj.ID;
}
else
{
// Else add it to the dictionary
obj.Properties.Add("id", obj.ID);
}
}
index++;
}
I believe the reason why your objects are not updating because it's probably still referring to the memory block before your objects were changed. Perhaps. The easiest way (that I can think of, there are thousands of smarter programmers than me) is to create a new list and have it contain all of your updated objects.
Edit
I updated the code above with the code that I have. I created a method to set a small amount of objects to test:
private static IEnumerable<MyData> GetMyData()
{
return new List<MyData>()
{
new MyData(),
new MyData() {ID = "2"},
new MyData() {ID = "3"},
new MyData()
};
}
I was able to view my changes and then go through a foreach loop to view my changes. If the ID of the object is Null or Empty, then it steps into the if check and adds the current index to the ID as you know.
Now for my question: Which "id" is blank? The "id" in the dictionary or is it the ID of the model? Are all of your (Model).ID blank? As the updated code of yours, if your dictionary doesn't have "id" as a key, it's going to throw an exception saying it doesn't exist so you will need to do a check to make sure it does exist or add it if it doesn't.
I have a listbox that prints the name of a custom item class
public class Item
{
public string #Url { get; set; }
public string Name { get; set; }
public double Price { get; set; }
public Item(string #url, string name, double price)
{
this.Url = url;
this.Name = name;
this.Price = price;
}
public override string ToString()
{
return this.Name;
}
}
I tried the normal method but because i have radio buttons to sort the list box it messes it up since index is changed.
EG
//new item is declared
Dictionary<int, Item> itemList = Dictionary<int, Item> { new Item("f.ca", "name1", 33);
new Item("m.ca", "name2", 44); }
//Items added to listbox
for (int v = 0; v < itemList.Count; v++)
{
itemListBox.Items.Add(itemList[v].Name);
}
//start sorting
var priceSort = from item in itemList
orderby item.Value.Price
select new { item.Value.Name, item.Value.Price };
itemListBox.Items.Clear();
foreach (var i in priceSort)
{
itemListBox.Items.Add(i.Name);
}
//end sorting listbox updated
now that the new list is created removing only the item in itemlist is necessary since the box is updated.
/* This code is what i thought but SelectedIndex say if on 0 and since the sorted by price */
itemList.Remove(itemListBox.SelectedIndex);
The issue being now its trying to remove items[0] when items[1] is really the one that needs to be removed. Is there a way i could make it compare the string of the itemlistbox to the .Name property of the items dictionary?
You stated that the key for your dictionary is determined by the current count of items in the dictionary. If that's the case, you'd have to do something like this:
var matches = itemList.Where(x => x.Name == itemListBox.SelectedValue);
if (matches.Any())
{
itemList.Remove(matches.First().Key);
}
But this is slow and inelegant. You're really not using the Dictionary class correctly. Dictionaries are ideal for performing quick access based on a known key value. If you have to search for the key every time, you loose all benefit the Dictionary provides.
You might as well use a simple List<Item> instead, using the FindIndex / RemoveAt methods:
var index = itemList.FindIndex(x => x.Name == itemListBox.SelectedValue);
if (index != -1)
{
itemList.RemoveAt(index);
}
This isn't a whole lot faster, but it's more elegant—lists are specifically designed to support this kind of thing without having to resort to Linq.
Or better yet, use the item's name as the dictionary key:
Dictionary<string, Item> itemList = Dictionary<string, Item>();
itemList.Add("name1", new Item("f.ca", "name1", 33));
itemList.Add("name2", new Item("m.ca", "name2", 44));
...
itemList.Remove(itemListBox.SelectedValue);
This is a much more efficient and elegant solution.
My domain object :
public class MyDomainObject
{
public Guid Id { get; set; }
public string Name { get; set; }
public int DisplayOrder { get; set; }
}
Assuming sample data :
var list = new List<MyDomainObject>()
{
new MyDomainObject {Name = "Element1", DisplayOrder = 0},
new MyDomainObject {Name = "Element2", DisplayOrder = 1},
new MyDomainObject {Name = "Element3", DisplayOrder = 2},
new MyDomainObject {Name = "Element4", DisplayOrder = 3},
};
Now i change the DisplayOrder of the "Element3" from 2 to 1. My list should looks like that :
Element1 (DisplayOrder = 0)
Element3 (DisplayOrder = 1)
Element2 (DisplayOrder = 2)
Element4 (DisplayOrder = 3)
Now i remove "Element3"
Element1 (DisplayOrder = 0)
Element2 (DisplayOrder = 1)
Element4 (DisplayOrder = 2)
So what's the best way to persist this mechanism to database ?
Basically i need a "ReOrderableCollection" which will be populated from database with an OrderBy "DisplayOrder" where Collection Index Match "DisplayOrder", and persist back items by assigning DisplayOrder from Collection Index.
I answered a previous/similar question about re-ordering here:
How to design table that can be re-sequenced?
This does a good job of resaving the Order with no gaps. Depending on the size the lists resaving the Order may be a perfectly viable option, for long lists Mark Byers' idea looks pretty good.
From your examples it seems that you always want the sequence to be without gaps, starting from zero. But this means that removing the first element will require updating the row in the database for every single item in your list. It's simple and it will work (and these are good things) but it's not always ideal. Since you asked for "the best way" without really specifying what you mean by that, allow me to suggest an alternative method:
What really matters with a DisplayOrder is not the actual values but their relative order. If you want to improve performance with the database, you could consider relaxing the requirement that there should be no gaps and then try to find the smallest number of changes to the DisplayOrders to ensure that the correct order is stored, even if gaps are present in the resulting sequence. If you do this then adding, removing or moving a single item will typically only require updating one row in the database, with the exception that occasionally other items will have to be moved to create a gap where an item must be inserted between two others that have consecutive DisplayOrders.
You can also minimize the number of times that a gap is not available by starting with DisplayOrder 100, 200, 300 and later allowing for example an insertion with DisplayOrder 150 in between (or perhaps use a real/float type instead of an integer).
Another advantage of this method is if you use a database data comparison tool to observe changes between the current version of the database and older versions it will be easier to see what modifications have been made to the display order. You will only see changes in the display order of items that have actually been moved by the user, rather than half the list change each time an item is removed. It will also reduce the size of backups if you use an incremental backup strategy.
I'd say though that these advantages are not significant advantages over the naive method for most cases. It depends on your system whether it is worth implementing this system or just keeping it simple. If in doubt, keep it simple. For systems with small lists, few modifications and where you don't care about the change history, overwriting the entire list with new DisplayOrders each time will probably be just fine.
For what I can see it seems that DisplayOrder has the same value of the index property of the collection. So I will try to use that instead of a DisplayOrder property. On the DB I will use the DisplayOrder column to read and save the items but not on the domain objects.
HTH
ema
Now I'm assuming that you do want to always reorganize your list so that the DisplayOrder starts at 0 and increases without gaps, and you want this to happen automatically. You could implement your own collection type and an interface IDisplayOrderable and have the members of your type that change the list also automaticaly update the DisplayOrder of the items in the collection. As opposed to my other answer which was about an alternative way to store the data in the datase, this answer shows how to write a client class that could make it easier to automatically synchronize the DisplayOrder in your objects with your list indexes so that when you are ready to submit the changes to the database, the DisplayOrder field is already set correctly for you.
I think the answer is best given as some source code:
using System;
using System.Collections.Generic;
using System.Linq;
interface IDisplayOrderable
{
int DisplayOrder { get; set; }
}
class ReorderableList<T> : IList<T> where T : IDisplayOrderable
{
List<T> list = new List<T>();
private void updateDisplayOrders()
{
int displayOrder = 0;
foreach (T t in list)
{
t.DisplayOrder = displayOrder++;
}
}
public ReorderableList() { }
public ReorderableList(IEnumerable<T> items)
{
list = new List<T>(items.OrderBy(item => item.DisplayOrder));
}
public void Insert(int index, T item)
{
list.Insert(index, item);
updateDisplayOrders();
}
public void Add(T item)
{
list.Add(item);
updateDisplayOrders();
}
public bool Remove(T item)
{
bool result = list.Remove(item);
if (result)
updateDisplayOrders();
return result;
}
public IEnumerator<T> GetEnumerator()
{
return list.GetEnumerator();
}
// TODO: Other members and methods required to implement IList<T>...
}
class Item : IDisplayOrderable
{
public string Name { get; set; }
public int DisplayOrder { get; set; }
}
class Program
{
static void Main()
{
Item foo = new Item { Name = "foo", DisplayOrder = 0 };
Item bar = new Item { Name = "bar", DisplayOrder = 1 };
Item baz = new Item { Name = "baz", DisplayOrder = 2 };
// Pretend this came from the database.
IEnumerable<Item> query = new Item[] { bar, foo };
// The constructor automatically reorder the elements.
ReorderableList<Item> items = new ReorderableList<Item>(query);
items.Add(baz);
items.Remove(foo);
items.Insert(1, foo);
foreach (Item item in items)
Console.WriteLine("{0} : {1}", item.Name, item.DisplayOrder);
}
}
Output:
bar : 0
foo : 1
baz : 2
Perhaps this was the sort of answer you were looking for?
I maybe founded a solution by creating a custom List which take an Lamba Expression in constructor parameter in order the list to be able to self update items property "DisplayOrder".
The sample class
public class MyItem
{
public string Name { get; set; }
public int DisplayOrder { get; set; }
}
The sample program
public class Program
{
static void Main(string[] args)
{
var list = new DisplayOrderableList<MyItem>(p => p.DisplayOrder)
{
new MyItem{ Name = "Item 1"},
new MyItem{ Name = "Item 2"},
new MyItem{ Name = "Item 3"},
};
var item = list.Where(p => p.Name == "Item 2").FirstOrDefault();
list.MoveUp(item);
list.ForEach(p => Console.WriteLine("{0}-{1}", p.Name, p.DisplayOrder));
Console.WriteLine();
list.MoveDown(item);
list.ForEach(p => Console.WriteLine("{0}-{1}", p.Name, p.DisplayOrder));
Console.WriteLine();
Console.ReadLine();
}
}
The custom implementation of DisplayOrderableList
public class DisplayOrderableList<T> : List<T>
{
#region Private Fields
private PropertyInfo _property;
#endregion
#region Constructors
public DisplayOrderableList(Expression<Func<T, int>> expression)
{
ValidateExpression(expression);
}
#endregion
#region Public Methods
public void MoveUp(T item)
{
if (!Contains(item))
throw new ArgumentNullException("item", "item doesn't exists in collection");
var idx = IndexOf(item);
RemoveAt(idx);
if (idx > 0)
Insert(idx - 1, item);
else
Insert(0, item);
UpdateDisplayOrder();
}
public void MoveDown(T item)
{
if (!Contains(item))
throw new ArgumentNullException("item", "item doesn't exists in collection");
var idx = IndexOf(item);
RemoveAt(idx);
if (idx + 1 > Count)
Add(item);
else
Insert(idx + 1, item);
UpdateDisplayOrder();
}
#endregion
#region Private Methods
private void UpdateDisplayOrder()
{
foreach (var item in this)
{
_property.SetValue(item, IndexOf(item), null);
}
}
#endregion
#region Expression Methods
private void ValidateExpression(Expression<Func<T, int>> expression)
{
var lamba = ToLambaExpression(expression);
var propInfo = ToPropertyInfo(lamba);
if (!propInfo.CanWrite)
{
throw new ArgumentException(String.Format("Property {0} as no setters", propInfo.Name));
}
_property = propInfo;
}
private static LambdaExpression ToLambaExpression(Expression expression)
{
var lambda = expression as LambdaExpression;
if (lambda == null)
{
throw new ArgumentException("Invalid Expression");
}
var convert = lambda.Body as UnaryExpression;
if (convert != null && convert.NodeType == ExpressionType.Convert)
{
lambda = Expression.Lambda(convert.Operand, lambda.Parameters.ToArray());
}
return lambda;
}
private static PropertyInfo ToPropertyInfo(LambdaExpression expression)
{
if (expression == null)
{
throw new ArgumentNullException("expression", "Expression cannot be null.");
}
var prop = expression.Body as MemberExpression;
if (prop == null)
{
throw new ArgumentException("Invalid expression");
}
var propInfo = prop.Member as PropertyInfo;
if (propInfo == null)
{
throw new ArgumentException("Invalid property");
}
return propInfo;
}
#endregion
}
This now get the following output :
Item 2-0
Item 1-1
Item 3-2
Item 1-0
Item 2-1
Item 3-2
It's a proof of concept and should be enhanced but it's a beggining.
What do you think about this ?
I know this is a old question, but the comments here and in another question helped me solve a similar issue and I wanted to provide my code in case it helps anyone else out looking for something similar. You can find my code at the following link:
How to design table that can be re-sequenced?