簡體   English   中英

C#將通用類作為事件參數傳遞

[英]C# Passing generic class as an event parameter

在過去的幾天里,我一直在使用泛型,但是在嘗試將泛型作為參數傳遞給事件/代理時遇到了一個問題。

一個非常友好的堆棧成員可以使我對上周五發布的泛型提出一個問題。 但是,我想再次提出來,因為我仍然不知道如何使它正常工作。

在下面的代碼中,您可以看到我有一個“目錄”類,該類可以引發一個事件,其中包含一個通用參數。

類“ MainWindow”預訂此事件,並且應與通用參數一起使用。

這是行不通的,因為事件必須指定委托的通用類型。

public class Catalog {

#region EVENTS

public delegate void GenericListItemCountChangedEvent<T>(object sender, GenericListItemCountChangedEventArgs<T> e) where T : BaseItem; 
//This is the point where it does not work, because I specify BaseItem as the type
public event GenericListItemCountChangedEvent<BaseItem> GenericListItemCountChanged;

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

public class GenericListItemCountChangedEventArgs<T> : EventArgs where T : BaseItem {
    private List<T> _changedList_propStore;
    public List<T> ChangedList {
        get {
            return _changedList_propStore;
        }
    }

    public GenericListItemCountChangedEventArgs(List<T> ChangedList){
        _changedList_propStore = ChangedList;
    }
}

#endregion EVENTS

}


public partial class MainWindow : Window{

   public MainWindow(){
      _catalog.GenericListItemCountChanged += (sender, e) => GenericListItemCountChanged(sender, e);
   }

   private void GenericListItemCountChanged<T>(object sender, Catalog.GenericListItemCountChangedEventArgs<T> e) where T : BaseItem {
       //Use Generic EventArgs
   }

}

有沒有辦法在“ MainWindow”類中接收通用參數? 還是我需要實施一些解決方法?

您可以使Catalog類通用。 那將允許您使用GenericListItemCountChangedEvent T

public class Catalog<T> where T: BaseItem
{
    public delegate void GenericListItemCountChangedEvent<T>(object sender, GenericListItemCountChangedEventArgs<T> e) where T : BaseItem;
    //This is the point where it does not work, because I specify BaseItem as the type
    public event EventHandler<GenericListItemCountChangedEventArgs<T>> GenericListItemCountChanged;

    private void RaiseGenericListItemCountChangedEvent(List<T> List)
    {
        if (GenericListItemCountChanged != null)
        {
            GenericListItemCountChanged(this, new GenericListItemCountChangedEventArgs<T>(List));
        }
    }

    public class GenericListItemCountChangedEventArgs<T> : EventArgs where T : BaseItem
    {
        private List<T> _changedList_propStore;
        public List<T> ChangedList
        {
            get
            {
                return _changedList_propStore;
            }
        }

        public GenericListItemCountChangedEventArgs(List<T> ChangedList)
        {
            _changedList_propStore = ChangedList;
        }
    }
}

public  class MainWindow 
{
    public MainWindow()
    {
        new Catalog<BaseItem>().GenericListItemCountChanged += (sender, e) => GenericListItemCountChanged(sender, e);
    }

    private void GenericListItemCountChanged<T>(object sender, Catalog<BaseItem>.GenericListItemCountChangedEventArgs<T> e) where T : BaseItem
    {
        //Use Generic EventArgs
    }
}

根據您的確切需求,您也許可以保留方法的通用方面。 但我承認,我不清楚您為什么要這么做。 該方法綁定到特定的委托類型,即方法專門引發的事件使用的類型。

使其具有通用性將具有什么價值? 您是否真的要使用各種不同的列表(每個元素都有不同的類型)來引發這一事件? 如果是這樣,事件處理程序應該如何知道針對該事件提出的列表? 我的意思是,可以通過反射來完成,但這並不是一個好的設計。

無論如何,如果您真的想編譯代碼,則需要對所涉及的類施加一些限制,並在委托類型聲明中使用接口而不是實際的類。

例如:

interface IBaseItemEventArgs<out T>
{
    IReadOnlyList<T> ChangedList { get; }
}

class GenericListItemCountChangedEventArgs<T> : EventArgs, IBaseItemEventArgs<T>
    where T : BaseItem
{
    private IReadOnlyList<T> _changedList_propStore;
    public IReadOnlyList<T> ChangedList
    {
        get
        {
            return _changedList_propStore;
        }
    }

    public GenericListItemCountChangedEventArgs(List<T> ChangedList)
    {
        _changedList_propStore = ChangedList.AsReadOnly();
    }
}

public delegate void
    GenericListItemCountChangedEvent<in T>(object sender, IBaseItemEventArgs<T> e)
    where T : BaseItem;

public static event
    GenericListItemCountChangedEvent<BaseItem> GenericListItemCountChanged;

private static void RaiseGenericListItemCountChangedEvent<T>(List<T> List)
    where T : BaseItem
{
    GenericListItemCountChangedEvent<T> handler = GenericListItemCountChanged;

    if (handler != null)
    {
        handler(null, new GenericListItemCountChangedEventArgs<T>(List));
    }
}

這聲明了接口IBaseItemEventArgs<out T> ,即T是協變的(即返回的實際類型可能比使用該接口的聲明中派生的類型更多),以及事件委托類型GenericListItemCountChangedEvent<in T> ,即T是協變的(即,分配給該方法的處理程序的委托的類型可能派生的參數少於該局部處理程序變量的聲明中使用的參數)。

這兩個共同允許:

  1. RaiseGenericListItemCountChangedEvent<T>()方法可隱式地從事件委托類型(其聲明類型比方法聲明中的T派生的類型少RaiseGenericListItemCountChangedEvent<T>()隱式轉換為該方法實際處理的處理程序類型。
  2. IBaseItemEventArgs<out T>接口具有一個返回相似協變接口對象IReadOnlyList<T>

當然,如果處理程序需要能夠修改列表,則代碼將無法編譯(不能使用IReadOnlyList<T> )。 但這是一件好事 如果呼叫者能夠使用比聲明的派生類型更多的派生列表元素預訂事件, 並且仍被允許更改列表,則它可以將錯誤類型的元素添加到列表中。 那根本不好。 :)因此,語言規則可防止您犯該錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM