【问题标题】:Passing a generic List<T> as a delegate parameter将泛型 List<T> 作为委托参数传递
【发布时间】:2015-01-09 08:32:55
【问题描述】:

我编写了一个事件,该事件应该将一个包含 (T) 类型的通用项目的列表传递给所有订阅者:

public delegate void GenericListItemCountChangedEvent(List<Object> sender, GenericListItemCountChangedEventArgs e);
public event GenericListItemCountChangedEvent GenericListItemCountChanged;

private void RaiseGenericListItemCountChanged<T>(List<T> List) where T : BaseElem {
    if (GenericListItemCountChanged != null)
        GenericListItemCountChanged(List as List<Object>, new GenericListItemCountChangedEventArgs(typeof(T)));
}

这是一个类的声明,它订阅了上面的事件:

 _catalog.GenericListItemCountChanged += (sender, e) => GenericListItemCountChanged(sender, e);

这是在订阅者内部转发事件的方法:

private void GenericListItemCountChanged(List<Object> sender, Catalog.GenericListItemCountChangedEventArgs e) {
    Catalog.ListTypes changedListType = Catalog.GetListTypeFromList(changedList); 
    //GetListTypeFromList expects parameter to be a type of <T> where T : BaseElem
}

显然,List&lt;Object&gt; 无法转换为 List&lt;T&gt; where T : BaseElem

如果您可以提供一种解决方案,在处理事件的方法中检索列表及其“真实”类型的项目,我会接受您的回答。
(恢复原List状态)

列表中项目的“真实”类型存储在 EventArgs 中。
但我不知道这是否能帮助我......

解决方案:
没有@ChrFin 的帮助,我无法解决这个问题,谢谢伙计!

公共类目录:对象

public delegate void GenericListItemCountChangedEvent(IEnumerable<BaseElem> sender, GenericListItemCountChangedEventArgs e);
public event GenericListItemCountChangedEvent GenericListItemCountChanged;

private void RaiseGenericListItemCountChangedEvent<T>(List<T> List) where T : BaseElem {
    if (GenericListItemCountChanged != null) {
        GenericListItemCountChanged(List, new GenericListItemCountChangedEventArgs());
    }
}
public void ForceRaiseGenericListItemCountChangedEvent<T>(List<T> List) where T : BaseElem {
    RaiseGenericListItemCountChangedEvent(List);
}

public class GenericListItemCountChangedEventArgs {
    public GenericListItemCountChangedEventArgs() {
    }
}
    public static ListTypes GetListTypeFromList<T>(IEnumerable<T> List) where T : BaseElem {
        Type typeofT = List.GetType().GetGenericArguments()[0];
        //typeofT now contains correct subtype of 'BaseElem'
        return ListTypes.SomeType //based on 'typeOfT'
    }

公共部分类 MainWindow : Window

    _catalog.GenericListItemCountChanged += (sender, e) => GenericListItemCountChanged(sender, e);
private void GenericListItemCountChanged(IEnumerable<BaseElem> sender, Catalog.GenericListItemCountChangedEventArgs e) {
            Catalog.ListTypes changedListType = Catalog.GetListTypeFromList(sender);
            //We now know the changed ListType
}

非常感谢!

【问题讨论】:

    标签: c# events generics type-conversion


    【解决方案1】:

    有两种(三种)方法可以解决这个问题:Covariance 和泛型:

    1) 泛型:
    您还需要创建一个通用委托:

    public class YourClass<T> where T : BaseElem
    {
        public delegate void GenericListItemCountChangedEvent<T>(List<T> sender,
                                 GenericListItemCountChangedEventArgs e);
        public event GenericListItemCountChangedEvent<T> GenericListItemCountChanged;
    
        private void RaiseGenericListItemCountChanged<T>(List<T> List)
        {
            if (GenericListItemCountChanged != null)
            {
                GenericListItemCountChanged(List,
                   new GenericListItemCountChangedEventArgs(typeof(T)));
            }
        }
    }
    

    当然,在这种情况下,您只能使用一种显式类型的基本类型 BaseElem

    2) 协方差:
    使用IEnumerable&lt;T&gt; 接口而不是显式类型来支持协方差:

    public delegate void GenericListItemCountChangedEvent(IEnumerable<BaseElem> sender,
                             GenericListItemCountChangedEventArgs e);
    public event GenericListItemCountChangedEvent GenericListItemCountChanged;
    
    private void RaiseGenericListItemCountChanged(IEnumerable<BaseElem> List)
    {
        if (GenericListItemCountChanged != null)
        {
            var itemType = List.Count() > 0 ? List.First().GetType() : typeof(BaseElem);
            GenericListItemCountChanged(List,
                new GenericListItemCountChangedEventArgs(itemType));
        }
    }
    

    3) 丑陋,但会起作用:铸造:

    public delegate void GenericListItemCountChangedEvent(List<BaseElem> sender,
                             GenericListItemCountChangedEventArgs e);
    public event GenericListItemCountChangedEvent GenericListItemCountChanged;
    
    private void RaiseGenericListItemCountChanged<T>(List<T> List) where T : BaseElem
    {
        if (GenericListItemCountChanged != null)
        {
            GenericListItemCountChanged(List.Cast<BaseElem>().ToList(),
                new GenericListItemCountChangedEventArgs(typeof(T)));
        }
    }
    

    【讨论】:

    • 感谢您本周第二次提供帮助 :) 您的第一个 sn-p 对我不起作用,因为触发事件的类是目录:对象。您的第二次剪断可能有效,但我不确定如何在订阅中使用 IList 。基本上如何从 IList 获取 List
    • @NoelWidmer: Basically how to get the List&lt;BaseElem&gt; from the IList&lt;BaseElem&gt; - 你不能(请参阅有关协方差的链接文章)! (请注意我对IEnumerable&lt;T&gt; 的更新,因为我刚刚发现IList&lt;T&gt; 不支持协方差)在这种情况下您需要使用接口,因为显式类型不一样并且不能“全局转换”,但是仅基于“每件商品”(参见第 3 个选项)。您是否需要特定的 List&lt;T&gt; 方法/扩展或者您不能使用 IEnumerable&lt;T&gt; 的原因是什么?
    • 我对接口没有太多经验。这就是为什么我不知道 'IEnumerable' 是否有效。我想在 'GetListTypeFromList();' 中收到一个 'List'我不能改变这个方法来期待一个'IEnumerable',因为它经常使用。我想我无法从 'IEnumerable' 获得 'List'?
    • @NoelWidmer:您可以 - 请参阅我的第三个示例中的 ToList。但这会创建一个新列表 => 如果您有可能的项目或经常这样做,则速度会很慢。为什么不能改变方法? List&lt;T&gt; 实现 IEnumerable&lt;T&gt; => 您不需要更改对方法的调用...
    • 是的!我能够做到。如果您有兴趣:我用特定的解决方案更新了问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-29
    • 2011-05-29
    • 1970-01-01
    • 2021-10-18
    • 2021-06-23
    • 1970-01-01
    相关资源
    最近更新 更多