Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. Hey Marc Clifton!

Hey Marc Clifton!

Scheduled Pinned Locked Moved The Lounge
16 Posts 8 Posters 2 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • realJSOPR Offline
    realJSOPR Offline
    realJSOP
    wrote on last edited by
    #1

    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.

    K V Richard DeemingR M B 7 Replies Last reply
    0
    • realJSOPR realJSOP

      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.

      K Offline
      K Offline
      Kevin Marois
      wrote on last edited by
      #2

      Awesome. Write it up as a tip with some examples.

      If it's not broken, fix it until it is

      1 Reply Last reply
      0
      • realJSOPR realJSOP

        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.

        K Offline
        K Offline
        Kevin Marois
        wrote on last edited by
        #3

        So I just did this:

        class Program
        {
        static List people = new List();
        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("Name", "Pete");
            var person2 = people.FindFirstExact("Name", "Walter");
            var person3 = people.FindLastExact("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 FindExact(this List list, string valuePropertyName, P propertyValue)
        {
        List found = default(List);
        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

        realJSOPR 1 Reply Last reply
        0
        • realJSOPR realJSOP

          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.

          V Offline
          V Offline
          Vincent Blais
          wrote on last edited by
          #4

          Nice one The only thing I would change is to use an IEnumerable instead of a List. 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 people = new List();
          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("Name", "Pete");
              var person2 = people.FindFirstExact("Name", "Walter");
              var person3 = people.FindLastExact("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 FindExact(this IEnumerable list, string valuePropertyName, string text)
          {
          IEnumerable found = default(IEnumerable);
          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(this IEnumerable list, string valuePropertyName, string text)
          {
          	T found = default(T);
          	try
          	{
          		found = list.FindExact(valuePropertyName, text).FirstOrDefault();
          	}
          	catch (Exception)
          	{
          	}
          	return found;
          }
          
          public static T FindLastExact(this IEnumerable list, string valuePropertyName, string text)
          {
          	T found = default(T);
          	try
          	{
          		// Using Reverse here to not loop through the whole collection. 
          		// Could add a check if here if IList is implemented and only use LastOrDefault() in that case
          		found = list.Reverse().FindExact(valuePropertyName, text).First();
          	}
          	catch (Exception)
          	{
          	}
          	return found;
          }
          

          }

          Vince Remember the dead, fight for the living

          1 Reply Last reply
          0
          • realJSOPR realJSOP

            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.

            Richard DeemingR Offline
            Richard DeemingR Offline
            Richard Deeming
            wrote on last edited by
            #5

            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

            "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

            realJSOPR V 3 Replies Last reply
            0
            • K Kevin Marois

              So I just did this:

              class Program
              {
              static List people = new List();
              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("Name", "Pete");
                  var person2 = people.FindFirstExact("Name", "Walter");
                  var person3 = people.FindLastExact("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 FindExact(this List list, string valuePropertyName, P propertyValue)
              {
              List found = default(List);
              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

              realJSOPR Offline
              realJSOPR Offline
              realJSOP
              wrote on last edited by
              #6

              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

              1 Reply Last reply
              0
              • Richard DeemingR Richard Deeming

                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

                realJSOPR Offline
                realJSOPR Offline
                realJSOP
                wrote on last edited by
                #7

                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

                Richard DeemingR 1 Reply Last reply
                0
                • Richard DeemingR Richard Deeming

                  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

                  V Offline
                  V Offline
                  Vincent Blais
                  wrote on last edited by
                  #8

                  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

                  1 Reply Last reply
                  0
                  • realJSOPR realJSOP

                    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

                    Richard DeemingR Offline
                    Richard DeemingR Offline
                    Richard Deeming
                    wrote on last edited by
                    #9

                    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

                    "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                    D 1 Reply Last reply
                    0
                    • realJSOPR realJSOP

                      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.

                      M Offline
                      M Offline
                      Mark_Wallace
                      wrote on last edited by
                      #10

                      Damn! You're not as stupid as I look!

                      I wanna be a eunuchs developer! Pass me a bread knife!

                      1 Reply Last reply
                      0
                      • realJSOPR realJSOP

                        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.

                        B Offline
                        B Offline
                        BillWoodruff
                        wrote on last edited by
                        #11

                        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

                        1 Reply Last reply
                        0
                        • Richard DeemingR Richard Deeming

                          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

                          realJSOPR Offline
                          realJSOPR Offline
                          realJSOP
                          wrote on last edited by
                          #12

                          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

                          Richard DeemingR 1 Reply Last reply
                          0
                          • realJSOPR realJSOP

                            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.

                            M Offline
                            M Offline
                            Middle Manager
                            wrote on last edited by
                            #13

                            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:

                            1 Reply Last reply
                            0
                            • Richard DeemingR Richard Deeming

                              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

                              D Offline
                              D Offline
                              Dan Neely
                              wrote on last edited by
                              #14

                              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 DeemingR 1 Reply Last reply
                              0
                              • realJSOPR realJSOP

                                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

                                Richard DeemingR Offline
                                Richard DeemingR Offline
                                Richard Deeming
                                wrote on last edited by
                                #15

                                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

                                "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                                1 Reply Last reply
                                0
                                • D Dan Neely

                                  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 DeemingR Offline
                                  Richard DeemingR Offline
                                  Richard Deeming
                                  wrote on last edited by
                                  #16

                                  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

                                  "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

                                  1 Reply Last reply
                                  0
                                  Reply
                                  • Reply as topic
                                  Log in to reply
                                  • Oldest to Newest
                                  • Newest to Oldest
                                  • Most Votes


                                  • Login

                                  • Don't have an account? Register

                                  • Login or register to search.
                                  • First post
                                    Last post
                                  0
                                  • Categories
                                  • Recent
                                  • Tags
                                  • Popular
                                  • World
                                  • Users
                                  • Groups