简体   繁体   中英

How to declare a needed event in an interface?

My console application must be able to get data from two different datasources that must implement an interface named IDataSource . When data are received the dataSource object must raise an event named OnHistoricalDataReceived .

I created the EventArgs :

public class HistoricalDataReceivedEventArgs : EventArgs
{
    public IDataSource DataSource {get; set;}
    public string Symbol {get; set;}
    public List<DailyPrice> Data {get;set;}

    public HistoricalDataReceivedEventArgs(IDataSource dataSource, string symbol, List<DailyPrice> data)
    {
        DataSource = dataSource;
        Symbol = symbol;
        Data = data;
    }
}

I created the interface IDataSource :

public interface IDataSource
{
    event EventHandler<HistoricalDataReceivedEventArgs> OnHistoricalDataReceived;
    List<DailyPrice> RequestHistoricalData(string symbol, List<PriceField> fields, DateTime? firstDate=null, DateTime? lastDate=null);
}

Then I created two simple classes, one for Bloomberg and one for Reuters:

public class Bloomberg: IDataSource
{
    public delegate void HistoricalDataReceivedEventRaiser(HistoricalDataReceivedEventArgs args);
    public event HistoricalDataReceivedEventRaiser OnHistoricalDataReceived;

    public List<DailyPrice> RequestHistoricalData(string symbol, List<PriceField> fields, DateTime? firstDate=null, DateTime? lastDate=null)
    {
    var data = new List<DailyPrice>(); 

    // ... get the data

    var args = new HistoricalDataReceivedEventArgs(dataSource: this, symbol: symbol, data: data);
        if (OnHistoricalDataReceived!=null)
        {
            OnHistoricalDataReceived(args);
        }
    }
}

public class Reuters: IDataSource
{
    public delegate void HistoricalDataReceivedEventRaiser(HistoricalDataReceivedEventArgs args);
    public event HistoricalDataReceivedEventRaiser OnHistoricalDataReceived;

    public List<DailyPrice> RequestHistoricalData(string symbol, List<PriceField> fields, DateTime? firstDate=null, DateTime? lastDate=null)
    {
        var data = new List<DailyPrice>(); 

    // ... get the data

    var args = new HistoricalDataReceivedEventArgs(dataSource: this, symbol: symbol, data: data);
        if (OnHistoricalDataReceived!=null)
        {
            OnHistoricalDataReceived(args);
        }
    }
}

All the code work If I avoid to put this line in my interface:

event EventHandler<HistoricalDataReceivedEventArgs> OnHistoricalDataReceived;

But I want that every object that implements the interface will raise this event when the data are retrieved.

If I try to compile the compiler complains:

'Bloomberg' does not implement interface member 'IDataSource.OnHistoricalDataReceived'. 'Bloomberg.OnHistoricalDataReceived' cannot implement 'IDataSource.OnHistoricalDataReceived' because it does not have the matching return type of 'EventHandler'.

'Reuters' does not implement interface member 'IDataSource.OnHistoricalDataReceived'. 'Reuters.OnHistoricalDataReceived' cannot implement 'IDataSource.OnHistoricalDataReceived' because it does not have the matching return type of 'EventHandler'.

I tried many variation without any success. What is the right way to specify in my interface I want the OnHistoricalDataReceived event?

You need to implement the event in your classes, but instead you created two new delegate types and used them as the event's type.

You implement the event just like you declared it in the interface:

public class Bloomberg: IDataSource
{
    public event EventHandler<HistoricalDataReceivedEventArgs> OnHistoricalDataReceived;

    public List<DailyPrice> RequestHistoricalData(string symbol, List<PriceField> fields, DateTime? firstDate=null, DateTime? lastDate=null)
    {
        var data = new List<DailyPrice>(); 

        // ... get the data

        var args = new HistoricalDataReceivedEventArgs(dataSource: this, symbol: symbol, data: data);
        if (OnHistoricalDataReceived!=null)
        {
            OnHistoricalDataReceived(this, args); // use "this" as sender
        }
    }
}

public class Reuters: IDataSource
{
    public event EventHandler<HistoricalDataReceivedEventArgs> OnHistoricalDataReceived;

    public List<DailyPrice> RequestHistoricalData(string symbol, List<PriceField> fields, DateTime? firstDate=null, DateTime? lastDate=null)
    {
        var data = new List<DailyPrice>(); 

        // ... get the data

        var args = new HistoricalDataReceivedEventArgs(dataSource: this, symbol: symbol, data: data);
        if (OnHistoricalDataReceived!=null)
        {
            OnHistoricalDataReceived(this, args); // use this as sender
        }
    }
}

Note that (in C#6) you can do this:

OnHistoricalDataReceived?.Invoke(this, args);

This is thread-safe. Your current code can break if the event is unsubscribed by another thread again after the null-check.

Before C# 6 you should have done this:

var handler = OnHistoricalDataReceived; // save the reference
if (handler != null) handler(this, args); // use the local (unchanged) variable

Please change your interface to:

public interface IDataSource
{
    event HistoricalDataReceivedEventRaiser OnHistoricalDataReceived;
    List<DailyPrice> RequestHistoricalData(string symbol, List<PriceField> fields, DateTime? firstDate=null, DateTime? lastDate=null);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM