Hey Marc Clifton!
-
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 aList<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 astring
, and doesn't have any index parameters; and by checking that the item is notnull
. 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 fornull
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 notnull
.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 -
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 aList<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 astring
, and doesn't have any index parameters; and by checking that the item is notnull
. 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 fornull
all the time.
"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:
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 notnull
.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, 2013But 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
-
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.
Damn! You're not as stupid as I look!
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.
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
-
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 aList<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 astring
, and doesn't have any index parameters; and by checking that the item is notnull
. 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 fornull
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:
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 -
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.
Wow! I made something remarkably similar last night (i.e. string parsing) after having read Marc's post and having the need. Your solution has more elegance than mine me thinks. Thanks to both of you. :thumbsup:
-
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 :omg: :wtf: 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
-
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, 2013John Simmons / outlaw programmer wrote:
It is, after all, a list of
<T>
, so no item in the list will/should be nullThere'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
-
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 :omg: :wtf: 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