开发者

Passing delegate with template args as parameter

I'm struggling with the code below.

I have a method Find, which for me is generic in terms I can use it for different type deriving from the same base class. Inside this method I used to have a delegate passed to the FindAll call. I removed this delegate and I'm trying to pass it as parameter, so more methods can use the Find method with different filtering criteria.

The problem is that the Filter delegate must be able to accept a Template type as argument, and the compiler is complaining that the parameters to the Find method doesn't match. The problem happens inside the method FindItems when I call Find.

Any ideas? Many thanks

    delegate bool FindFilter<T_Item>(T_Item item);

    private List<MailItem> Find<T_Item, T_Adaptor>(T_Adaptor adaptor, MailItemId mailId, FindFilter filter)
    {
            List<T_Item> tempList = ((List<T_Item>)(typeof(T_Adaptor).InvokeMember(
                    "Load",
                    BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod,
                    null, adaptor,
                    new Object[] { null, mailId, null })));

            totalItemsFound = tempList.Count;

            List<T_Item> Items = tempList.FindAll(
                            filter()
                        );

        List<MailItem> mailItems = new List<MailItem>();
        foreach (T_Item itm in Items)
            mailItems.Add(itm as MailItem);

        return mailItems;
    }

        private static bool FindAssignedItemsOnly<T_Item>(T_Item itm)
        {
            MailItem mi = itm as MailItem;
            if (mi == null) return false;
            retur开发者_如何学Gon (mi.StateInd.Code == StateInd.ASSIGNED);
        }

    public List<MailItem> FindItems(MailItemId itemId, string mailCategoryCd)
    {
        List<MailItem> mailItems = new List<MailItem>();

            FindFilter<MailItem> f = FindAssignedItemsOnly;
           // Problem happens in the line below
            mailItems = Find<Letter, BasicItemAdapter>(new LetterItemAdapter(), itemId, f); 

        return mailItems;
    }


I made some changes:

to FindItems, change f to FindFilter<BasicItem>:

    FindFilter<BasicItem> f = FindAssignedItemsOnly;
    // Problem happens in the line below
    mailItems = Find<BasicItem, BasicItemAdapter>(new BasicItemAdapter(), itemId, f);

and to Find, use the FindFilter generic type:

 private List<MailItem> Find<T_Item, T_Adaptor>(T_Adaptor adaptor,
    MailItemId mailId, FindFilter<T_Item> filter)

and changed the main search:

List<T_Item> Items = tempList.FindAll(row => filter(row));

and it compiles; obviously I can't test it since I had to invent a lot of code...


One thing I see is that in your code where you call the FindAll method you are trying to use the filter variable as a method. Remove the Parens...

I do stuff like this all the time. As a matter of fact I have written several generic processes similar to this.

The find delegate has to match Predicate so any method that does so will do this. So for example say you wanted to do something crazy like use reflection for your filter you could do something like this.

public class SimpleFind<T_Adaptor, T_Item>
{
   public T_Adaptor AdapterItem { get; set; }
   public SimpleFind(T_Adaptor item)
   {
      this.AdapterItem = item;
   }

   public bool FindMyStuff<T_Item>(T_Item value)
   {
      // Place your crazy reflection logic here...
      if (value.Property == AdapterItem.Property) return true;
      else return false;
   }
}

Then your list would use it like so directly:

List<T_ITem> items = myItems.Find(new SimpleFind<T_Adaptor, T_Item>(adapterValue).Find);

or in the case of your method where you have passed in the predicate delegate already defined:

List<T_ITem> items = myItems.Find(filter);

I have not compiled this and this is just an assumption that the two generics have matching values but I wanted to show the effect of how you can extend this.

However based on what I can see in your code your filter should work if you remove the parens on your filter call since it is a delegate in the correct pattern for the Predicate type.


Thanks for all the comments, they helped me a lot. At the end, I just changed the lambda call suggested by Marc as not always I want to filter:

List<T_Item> Items = tempList.FindAll(
                                                    delegate(T_Item itm) 
                                                        { 
                                                            if (filter == null) 
                                                                return true;
                                                            return filter(itm); 
                                                        }
                                                );
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜