How can I access a property dynamically by name without using reflection? - c#

At first I was using:
sortedList = unsorted.AsParallel().OrderBy(myItem => TypeDescriptor.GetProperties(myItem)[firstSort.Item2].GetValue(myItem));
Where firstSort.Item2 was the string name of the property. However, the performance degraded significantly as the number of items in the unsorted list increased. (As I expected)
Is there a way to do this without using reflection?
The brute force approach would be to do something like:
if(firstSort.Item2 == "Size")
sortedList = unsorted.AsParallel().OrderBy(myItem => myItem.Size);
else if(firstSort.Item2 == "Price")
sortedList = unsorted.AsParallel().OrderBy(myItem => myItem.Price);
...
I'm looking for something that would accomplish the above behavior, but without having to hardcode in all the different properties in the interface.

Everything you use that doesn't involve a hard-coded list of actual properties, will be using Reflection "behind the scenes".

You can use Expression<T> to pre-compile the expressions that you're passing to OrderBy. Then you can look them up at runtime.

You can create the PropertyInfo once and use it to call GetValue over multiple target objects. This will be much less expensive than calling TypeDescriptor.GetProperties for every item in the list.
Also, try removing AsParallel - the overhead may actually be reducing performance rather than helping it in this case.
Try this:
var prop = unsorted.GetType().GetGenericArguments()[0].GetProperty(firstSort.Item2);
sortedList = unsorted.OrderBy(myItem => prop.GetValue(myItem, null));

If you implement ICustomTypeDescriptor in your class, then you can avoid the reflection when using TypeDescriptor.
Of course, I'm assuming you own the type of myItem.

Your best bet is to use the Dynamic LINQ library provided by Microsoft.
Here is a link: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

I like Roger's answer the best for a true solution, but if you want something simple, you can build a small code generator to take the class and break out its properties into a dictionary of string to lambda, representing each property. At runtime, you could call from this dictionary to retrieve the appropriate lambda.

You can use the DLR. The open source framework Impromptu-Interface does all the dlr plumbing behind the scenes and and gets the value of a property 2.5x faster than reflection.
sortedList = unsorted.AsParallel().OrderBy(myItem => Impromptu.InvokeGet(myItem,firstSort.Item2));

Related

Manually removing items from a collection vs using Enumerable.Except C#

To remove objects from a List of custom objects using Except method requires you to implement a IEqualityComparer on the object. But is it bad just to remove the objects in a normal foreach loop?
I understand the concept of the IEqualityComparer and using Except but I couldn't get it to work for some reason so I just removed the items manually. Is this considered bad programming?
EDIT: using the manual way id have to override Equals and GetHashcode polluting my view model - I guess that's bad?
In general, one should avoid making changes to a collection while enumerating.
I'm not entirely sure what your original problem is, or why you need to remove elements in such a way, but you're over-complicating the problem. If I understand it right, and you are in fact using a List<T> where T is a custom type. If this is the case, then simply use a LINQ query to get the values you want from the list.
var newList = oldList.Where(x => x.PropertyName != unwantedValue);
You could use Enumerable.Except, but it should be noted that Enumerable.Except returns a set, which is to say, no duplicate values are allowed.
Also, it should be noted that overriding .Equals and .GetHashCode does not pollute the viewmodel, as far as I know.
Sources:
http://msdn.microsoft.com/en-us/library/vstudio/bb336390(v=vs.100).aspx
Enumerable.Except Problem

Is there any way to make right to left value assigning in linq or in any other way

The title is pretty unclear. But I couldn't find the proper words. Generally Linq works in the below syntax
MyList.Where().Select(x => {MyFunction(x);})
It is good in ordinary conditions but in some situation like in my case. I am creating a tree structure using dictionary. In this if I want to add a set
Set.Foreach(x => {(MyDict[logEvent.level][logEvent.event][logEvent.subevent][logEvent.filePath]).Add(x);});
But it would be nice if I can do like below
(MyDict[logEvent.level][logEvent.event][logEvent.subevent][logEvent.filePath]).Add(MySet.Foreach(x => {return x;}));
Is there any way possible to dothis ?
You can do it, if object stored in Dict has AddRange method which accepts IEnumerable<T>. But you should ski[ ForEach and just pass MySet:
MyDict[logEvent.level][logEvent.event][logEvent.subevent][logEvent.filePath]).AddRange(MySet);

c# in memory query of objects without linq

We are still using .Net Framework 2.0 / VS 2005 so i do not have LINQ. If i don't want to go with the poor man's LINQ solution, what are some other alternatives for being able to query in memory custom objects in a dictionary?
I'm not sure if one of your poor man's LINQ solution is LINQBridge but I used it for a few weeks and it seemed to be working okay before we actually switched to .NET 3.5 and the real deal.
Dictionary<T> would seem like a good choice, although you haven't provided much information about what you mean by "query." Are you just looking to retrieve data based on some key value? Get a count of total items? Do a sum or average based on some condition? You really need to give more information to get a better answer.
To elaborate on what Chesso said, you'll have to iterate the loop just like LINQ does...
for example:
static T FindFirst<T>(IEnumerable<T> col, Predicate<T> predicate)
{
foreach(T t in col)
{
if(predicate(t))
{
return t;
}
}
return default(T);
}
I was not aware of the Predicate delegate, that seems to be pretty much what i was looking for. As far as the context for which i'm querying:
Say i have a object X with properties A (name, guaranteed to be unique) and B (age)
1) I have a series of objects in a dictionary whose keys are say Property A of a given object, and of course the value is the object iself.
Now i want to retrieve all objects in this dictionary which meet a certain criteria of B, say age > 20.
I can add all the values of the dictionary into a list then call the .FindAll on it, passing in a delegate. I can create an anonymous delegate to do this, but say i will reuse this many times. How can i dynamically specify an age criteria for the delegate method? Would the only choice be to encapsulate the Predicate method in a class, then create a new instance of that class with my criteria as an instance variable?

How to optimize this code

it has a property:
string Code
and 10 other.
common codes is list of strings(string[] )
cars a list of cars(Car[])
filteredListOfCars is List.
for (int index = 0; index < cars.Length; index++)
{
Car car = cars[index];
if (commonCodes.Contains(car.Code))
{
filteredListOfCars.Add(car);
}
}
Unfortunately this piece of methodexecutes too long.
I have about 50k records
How can I lower execution time??
The easiest optimization isto convert commonCodes from a string[] to a faster lookup structure such as a Dictionary<string,object> or a HashSet<string> if you are using .Net 3.5 or above. This will reduce the big O complexity of this loop and depending on the size of commonCodes should make this loop execute faster.
Jared has correctly pointed out that you can optimize this with a HashSet, but I would also like to point out that the entire method is unnecessary, wasting memory for the output list and making the code less clear.
You could write the entire method as:
var commonCodesLookup = new HashSet<int>(commonCodes);
var filteredCars = cars.Where(c => commonCodesLookup.Contains(c.Code));
Execution of the filteredCars filtering operation will be deferred, so that if the consumer of it only wants the first 10 elements, i.e. by using filteredCars.Take(10), then this doesn't need to build the entire list (or any list at all).
To do what you want, I would use the Linq ToLookup method to create an ILookup instead of using a dictionary. ToLookup was made especially for this type of scenario. It is basically an indexed look up on groups. You want to group your cars by Code.
var carCodeLookup = cars.ToLookup(car => car.Code);
The creation of the carCodeLookup would be slow but then you can use it for fast lookup of cars based on Code. To get your list of cars that are in your list of common codes you can do a fast lookup.
var filteredCarsQuery = commonCodes.SelectMany(code => carCodeLookup[code]);
This assumes that your list of cars does not change very often and it is your commonCodes that are dynamic between queries.
you could use the linq join command, like
var filteredListOfCars = cars.Join(commonCodes, c => c.Code, cC => cC, (car, code) => car).ToArray();
Here's an alternative to the linq options (which are also good ideas): If you're trying to do filtering quickly, I would suggest taking advantage of built in types. You could create a DataTable that has two fields, the id of the car in your array, and the code (you can add the other 10 things if they matter as well). Then you can create a DataView around it and use the filter property of that. It uses some really fast indexing internally (B-trees I believe) so you probably won't be able to beat its performance manually unless you're an algorithms whiz, which if you were, you wouldn't be asking here. It depends what you're doing and how much performance matters.
It looks like what you're really checking is whether the "code" is common, not the car. You could consider a fly weight pattern, where cars share common instances of Code objects. The code object can then have an IsCommon property and a Value property.
You can then do something to the effect of updating the used Code objects whenever the commoncodes list changes.
Now when you do your filtering you only need to check each car code's IsCommon property

Dynamic "WHERE" like queries on memory objects

What would be the best approach to allow users to define a WHERE-like constraints on objects which are defined like this:
Collection<object[]> data
Collection<string> columnNames
where object[] is a single row.
I was thinking about dynamically creating a strong-typed wrapper and just using Dynamic LINQ but maybe there is a simpler solution?
DataSet's are not really an option since the collections are rather huge (40,000+ records) and I don't want to create DataTable and populate it every time I run a query.
What kind of queries do you need to run? If it's just equality, that's relatively easy:
public static IEnumerable<object[]> WhereEqual(
this IEnumerable<object[]> source,
Collection<string> columnNames,
string column,
object value)
{
int columnIndex = columnNames.IndexOf(column);
if (columnIndex == -1)
{
throw new ArgumentException();
}
return source.Where(row => Object.Equals(row[columnIndex], value);
}
If you need something more complicated, please give us an example of what you'd like to be able to write.
If I get your point : you'd like to support users writting the where clause externally - I mean users are real users and not developers so you seek solution for the uicontrol, code where condition bridge. I just though this because you mentioned dlinq.
So if I'm correct what you want to do is really :
give the user the ability to use column names
give the ability to describe a bool function (which will serve as where criteria)
compose the query dynamically and run
For this task let me propose : Rules from the System.Workflow.Activities.Rules namespace. For rules there're several designers available not to mention the ones shipped with Visual Studio (for the web that's another question, but there're several ones for that too).I'd start with Rules without workflow then examine examples from msdn. It's a very flexible and customizable engine.
One other thing: LINQ has connection to this problem as a function returning IQueryable can defer query execution, you can previously define a query and in another part of the code one can extend the returned queryable based on the user's condition (which then can be sticked with extension methods).
When just using object, LINQ isn't really going to help you very much... is it worth the pain? And Dynamic LINQ is certainly overkill. What is the expected way of using this? I can think of a few ways of adding basic Where operations.... but I'm not sure how helpful it would be.
How about embedding something like IronPython in your project? We use that to allow users to define their own expressions (filters and otherwise) inside a sandbox.
I'm thinking about something like this:
((col1 = "abc") or (col2 = "xyz")) and (col3 = "123")
Ultimately it would be nice to have support for LIKE operator with % wildcard.
Thank you all guys - I've finally found it. It's called NQuery and it's available from CodePlex. In its documentation there is even an example which contains a binding to my very structure - list of column names + list of object[]. Plus fully functional SQL query engine.
Just perfect.

Categories

Resources