|
Hm, glad I use g++ for my own applications. And as an embedded developer, I really don't have to use VS.
|
|
|
|
|
Wordpress site showing thousands of modified files every day - normal process for database website or not?
|
|
|
|
|
Think you need to take this and the other question to the Q&A section.....the lounge is not where this belongs!
|
|
|
|
|
You may have been the victim of a spam attack.
|
|
|
|
|
Bloody vikings!
I wanna be a eunuchs developer! Pass me a bread knife!
|
|
|
|
|
I thought Vikings had better taste.
|
|
|
|
|
Depends upon how you cook them.
|
|
|
|
|
How is the express module both a function/method AND an object with properties?
|
|
|
|
|
Think you need to take this and the other question to the Q&A section.....the lounge is not where this belongs!
|
|
|
|
|
Wrong forum. You want this one[^]
I wanna be a eunuchs developer! Pass me a bread knife!
|
|
|
|
|
Welcome to yet another example of real-world application of an existing .Net feature.
A few days ago, Mac Clifton made a Lounge post describing a little-known LINQ feature - the let clause. I'm sure several of you were wondering if you'd ever find a reason to use let in your own code. Well, I was writing some code today, and decided this would be a perfect example.
The code in question is a List extension method which matches a named property to the specified text, and returns the first item whose (named) property is equal to that specified text.
Without further ado, here's the method:
public static List<T> FindExact<T>(this List<T> list, string valuePropertyName, string text)
{
List<T> found = default(List<T>);
try
{
PropertyInfo info = typeof(T).GetProperty(valuePropertyName);
found = (from item in list
let value = (string)(info.GetValue(item, null))
where value == text
select item).ToList();
}
catch (Exception)
{
}
return found;
}
public static T FindFirstExact<T>(this List<T> list, string valuePropertyName, string text)
{
T found = default(T);
try
{
found = list.FindExact(valuePropertyName, text).FirstOrDefault();
}
catch (Exception)
{
}
return found;
}
public static T FindLastExact<T>(this List<T> list, string valuePropertyName, string text)
{
T found = default(T);
try
{
found = list.FindExact(valuePropertyName, text).LastOrDefault();
}
catch (Exception)
{
}
return found;
}
The first thing I do is set found to default(T) (the only valid way to set a value to null in a method that uses generic types).
Next, I get the property info for the named property.
Finally, I use LINQ to find the first item whose (named) property matches the specified text.
If an exception is thrown at any point in the method, a null result is returned.
(In hindsight, it might be better to return a list of matching items instead of the first one, but you get the point.)
EDIT =============================
I changed the code to be more flexible for my needs - I actually need to be able to find the first and/or last match, but don't care about anything between.
".45 ACP - because shooting twice is just silly" - JSOP, 2010
- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
modified 9-Jun-16 13:04pm.
|
|
|
|
|
Awesome. Write it up as a tip with some examples.
If it's not broken, fix it until it is
|
|
|
|
|
So I just did this:
class Program
{<br />
static List<Person> people = new List<Person>();
static void Main(string[] args)
{
people.Add(new Person { Name = "Joan", Age = 102 });
people.Add(new Person { Name = "Pete", Age = 50 });
people.Add(new Person { Name = "Walter", Age = 65 });
people.Add(new Person { Name = "Joan", Age = 17 });
people.Add(new Person { Name = "Walter", Age = 25 });
var person1 = people.FindExact<Person>("Name", "Pete");
var person2 = people.FindFirstExact<Person>("Name", "Walter");
var person3 = people.FindLastExact<Person>("Name", "Joan");
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return Name + " - " + Age.ToString();
}
}
Works great - if what you're looking for is a string. Maybe enhance so I could search on any property type?
Something similar to this:
public static List<T> FindExact<T,P>(this List<T> list, string valuePropertyName, P propertyValue)
{
List<T> found = default(List<T>);
try
{
PropertyInfo info = typeof(T).GetProperty(valuePropertyName);
found = (from item in list
let value = (string)(info.GetValue(item, null))
where (P)value == propertyValue
select item).ToList();
}
catch (Exception)
{
}
return found;
}
(won't compile, but the idea is nice
If it's not broken, fix it until it is
modified 9-Jun-16 13:43pm.
|
|
|
|
|
This is specifically for finding objects in the list that contain the specified string. Feel free to adapt it to your needs.
".45 ACP - because shooting twice is just silly" - JSOP, 2010
- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
Nice one
The only thing I would change is to use an IEnumerable<t> instead of a List<t>.
That would make the extension method more flexible and make FindExact defered execution instead of greedy because of the toList()
Some quick write in LinqPad
void Main()
{
List<Person> people = new List<Person>();
people.Add(new Person { Name = "Joan", Age = 102 });
people.Add(new Person { Name = "Pete", Age = 50 });
people.Add(new Person { Name = "Walter", Age = 65 });
people.Add(new Person { Name = "Joan", Age = 17 });
people.Add(new Person { Name = "Walter", Age = 25 });
var person1 = people.FindExact<Person>("Name", "Pete");
var person2 = people.FindFirstExact<Person>("Name", "Walter");
var person3 = people.FindLastExact<Person>("Name", "Joan");
person1.Dump();
person2.Dump();
person3.Dump();
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return Name + " - " + Age.ToString();
}
}
public static class Extensions
{
public static IEnumerable<T> FindExact<T>(this IEnumerable<T> list, string valuePropertyName, string text)
{
IEnumerable<T> found = default(IEnumerable<T>);
try
{
PropertyInfo info = typeof(T).GetProperty(valuePropertyName);
found = from item in list
let value = (string)(info.GetValue(item, null))
where value == text
select item;
}
catch (Exception)
{
}
return found;
}
public static T FindFirstExact<T>(this IEnumerable<T> list, string valuePropertyName, string text)
{
T found = default(T);
try
{
found = list.FindExact(valuePropertyName, text).FirstOrDefault();
}
catch (Exception)
{
}
return found;
}
public static T FindLastExact<T>(this IEnumerable<T> list, string valuePropertyName, string text)
{
T found = default(T);
try
{
found = list.Reverse().FindExact(valuePropertyName, text).First();
}
catch (Exception)
{
}
return found;
}
}
Vince
Remember the dead, fight for the living
|
|
|
|
|
Not sure you really need let in that example:
public static IEnumerable<T> FindExact<T>(this IEnumerable<T> list, string valuePropertyName, string text)
{
IEnumerable<T> found = Enumerable.Empty<T>();
try
{
PropertyInfo info = typeof(T).GetProperty(valuePropertyName);
if (info != null && info.CanRead && info.PropertyType == typeof(string) && info.GetIndexParameters().Length == 0)
{
found = list.Where(item => item != null && (string)info.GetValue(item, null) == text).ToList();
}
}
catch (Exception)
{
}
return found;
}
As Vince said, it's probably better to use IEnumerable<T> , rather than a List<T> . You can still eagerly evaluate the sequence to prevent exceptions from being thrown during enumeration.
You can eliminate most of the exceptions be checking that the property is found, can be read, returns a string , and doesn't have any index parameters; and by checking that the item is not null .
And I'd be inclined to return an empty sequence if the property is invalid or you get an exception, so that you don't have to check the returned value for null all the time.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Richard Deeming wrote: You can eliminate most of the exceptions be checking that the property is found, can be read, returns a string , and doesn't have any index parameters; and by checking that the item is not null .
In the event of any exception, it returns null. There's no need for the extra sanity check code.
".45 ACP - because shooting twice is just silly" - JSOP, 2010
- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
But at what cost?
Throwing and catching an exception will seriously degrade your code's performance. When there's a simple sanity-check that can avoid the exception, it's always preferable to use it.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Richard Deeming wrote: Throwing and catching an exception will seriously degrade your code's performance.
That's only true if you're throwing them by default instead of exception and even then in the most trivial cases. In the real world once you go beyond trivial math/string fiddling to anything with a file or database access even using exceptions as your primary control method will have a negligible impact.
Performance implications of Exceptions in .NET[^]
Did you ever see history portrayed as an old man with a wise brow and pulseless heart, waging all things in the balance of reason?
Is not rather the genius of history like an eternal, imploring maiden, full of fire, with a burning heart and flaming soul, humanly warm and humanly beautiful?
--Zachris Topelius
Training a telescope on one’s own belly button will only reveal lint. You like that? You go right on staring at it. I prefer looking at galaxies.
-- Sarah Hoyt
|
|
|
|
|
It's still better to use simple sanity checks where possible.
This:
string name = (person != null) ? person.Name : string.Empty;
or, in C# 6:
string name = person?.Name ?? string.Empty;
is much better than:
string name = string.Empty;
try
{
name = person.Name;
}
catch (NullReferenceException)
{
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Good call on returning an empty sequence. More in line with the standards in Linq for a collection. I have missed that one.
Vince
Remember the dead, fight for the living
|
|
|
|
|
Richard Deeming wrote:
found = list.Where(item => item != null && (string)info.GetValue(item, null) == text).ToList();
Do you really think you need to check the item for null here? It is, after all, a list of <T> , so no item in the list will/should be null (unless you're doing some really weird stuff in terms of removal).
".45 ACP - because shooting twice is just silly" - JSOP, 2010
- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
John Simmons / outlaw programmer wrote: It is, after all, a list of <T> , so no item in the list will/should be null
There's no restriction on the generic type parameter, so it could quite easily be a reference type.
Lists of reference types can quite happily contain null items. No need for any "weird stuff"!
var listOfStrings = new List<string>();
listOfStrings.Add(null);
listOfStrings.Add(default(string));
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Damn! You're not as stupid as I look!
I wanna be a eunuchs developer! Pass me a bread knife!
|
|
|
|
|
Useful code, John, thanks ! Also a great discussion, the kind I most enjoy.
I second Kevin's suggestion you write this up as a tip/trick.
cheers, Bill
«There is a spectrum, from "clearly desirable behaviour," to "possibly dodgy behavior that still makes some sense," to "clearly undesirable behavior." We try to make the latter into warnings or, better, errors. But stuff that is in the middle category you don’t want to restrict unless there is a clear way to work around it.» Eric Lippert, May 14, 2008
modified 9-Jun-16 23:08pm.
|
|
|
|
|