使用模板args作为参数传递委托

时间:2010-12-07 10:25:00

标签: c# generics delegates

我正在努力解决以下代码问题。

我有一个方法Find,对我而言是通用的,我可以将它用于从同一基类派生的不同类型。在这个方法中,我曾经将一个委托传递给FindAll调用。我删除了这个委托,我试图将其作为参数传递,因此更多方法可以使用具有不同过滤条件的Find方法。

问题是Filter委托必须能够接受Template类型作为参数,并且编译器抱怨Find方法的参数不匹配。当我调用Find时,问题发生在方法FindItems中。

有什么想法吗?非常感谢

    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;
            return (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;
    }

3 个答案:

答案 0 :(得分:1)

我做了一些改变:

FindItems,将f更改为FindFilter<BasicItem>

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

Find,使用FindFilter泛型类型:

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

并更改了主搜索:

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

并编译;显然我无法测试它,因为我必须发明很多代码......

答案 1 :(得分:1)

我看到的一件事是,在您调用FindAll方法的代码中,您尝试使用过滤器变量作为方法。删除Parens ......

我一直这样做。事实上,我已经写了几个类似的通用过程。

find委托必须与Predicate匹配,因此任何执行此操作的方法都会执行此操作。因此,举例来说,你想做一些疯狂的事情,比如使用反射过滤你可以做类似的事情。

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;
   }
}

然后你的列表将直接使用它:

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

或者在您传入已定义的谓词委托的方法的情况下:

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

我还没有编译这个,这只是假设两个泛型具有匹配的值,但我想展示如何扩展它的效果。

但是,根据我在代码中看到的内容,如果删除过滤器调用中的parens,则过滤器应该有效,因为它是谓词类型的正确模式的委托。

答案 2 :(得分:0)

感谢所有评论,他们帮助了我很多。最后,我刚刚改变了Marc建议的lambda调用,因为并不总是想要过滤:

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