开发者

Can this extension method be improved?

开发者 https://www.devze.com 2022-12-28 08:09 出处:网络
I have the following extension method public static class ListExtensions { public static IEnumerable<T> Search<T>(this ICollection<T> collection, string stringToSearch)

I have the following extension method

public static class ListExtensions
    {

        public static IEnumerable<T> Search<T>(this ICollection<T> collection, string stringToSearch)
        {
            foreach (T t in collection)
            {
                Type k = t.GetType();
                PropertyInfo pi = k.GetProperty("开发者_StackOverflowName");
                if (pi.GetValue(t, null).Equals(stringToSearch))
                {
                    yield return t;
                }
            }
        } 

    }

What it does is by using reflection, it finds the name property and then filteres the record from the collection based on the matching string.

This method is being called as

List<FactorClass> listFC = new List<FactorClass>();
    listFC.Add(new FactorClass { Name = "BKP", FactorValue="Book to price",IsGlobal =false  });
    listFC.Add(new FactorClass { Name = "YLD", FactorValue = "Dividend yield", IsGlobal = false });
    listFC.Add(new FactorClass { Name = "EPM", FactorValue = "emp", IsGlobal = false });
    listFC.Add(new FactorClass { Name = "SE", FactorValue = "something else", IsGlobal = false });    
   List<FactorClass> listFC1 = listFC.Search("BKP").ToList();

It is working fine.

But a closer look into the extension method will reveal that

Type k = t.GetType();
PropertyInfo pi = k.GetProperty("Name");

is actually inside a foreach loop which is actually not needed. I think we can take it outside the loop.

But how?

PLease help. (C#3.0)


Using reflection in this way is ugly to me.

Are you sure you need a 100% generic "T" and can't use a base class or interface?

If I were you, I would consider using the .Where<T>(Func<T, Boolean>) LINQ method instead of writing your own Search function.

An example use is:

List<FactorClass> listFC1 = listFC.Where(fc => fc.Name == "BKP").ToList();


     public static IEnumerable<T> Search<T>(this ICollection<T> collection, string stringToSearch)
    {

            Type k = typeof(T);
            PropertyInfo pi = k.GetProperty("Name");

            foreach (T t in collection)
            {
             if (pi.GetValue(t, null).Equals(stringToSearch))
             {
                yield return t;
             }
            }
    } 


There's a couple of things you could do -- first you could institute a constraint on the generic type to an interface that has a name property. If it can only take a FactorClass, then you don't really need a generic type -- you could make it an extension to an ICollection<FactorClass>. If you go the interface route (or with the non-generic version), you can simply reference the property and won't have a need for reflection. If, for some reason, this doesn't work you can do:

 var k = typeof(T);
 var pi = k.GetProperty("Name");
 foreach (T t in collection)  
 {   
      if (pi.GetValue(t, null).Equals(stringToSearch))  
      {  
           yield return t;  
      }
 }  

using an interface it might look like

 public static IEnumerable<T> Search<T>(this ICollection<T> collection, string stringToSearch) where T : INameable
 {   
    foreach (T t in collection)   
    {      
        if (string.Equals( t.Name, stringToSearch))   
        {   
            yield return t;   
        }   
    }
 }

EDIT: After seeing @Jeff's comment, this is really only useful if you're doing something more complex than simply checking the value against one of the properties. He's absolutely correct in that using Where is a better solution for that problem.


Just get the type of T

        Type k = typeof(T);
        PropertyInfo pi = k.GetProperty("Name");
        foreach (T t in collection)
        {                
            if (pi.GetValue(t, null).Equals(stringToSearch))
            {
                yield return t;
            }
        }
0

精彩评论

暂无评论...
验证码 换一张
取 消