如何使用委托跨类触发事件?

时间:2019-04-03 14:19:00

标签: c# .net events delegates publish-subscribe

我有2个不同的类,需要在main方法中订阅事件。但是我没有在main方法中订阅事件。有人知道怎么做吗?

First Class
***********
public class Data
{
    public string ID { get; set; }
    public string Description { get; set; }
}

public class ClsSub
{
    public delegate void datahandler(Data dt);

    public event LogHandler OnDataRetrieved;

    public void LoadData()
    {
        DataTable dt = GetData();
        Data logdata = new Data ();

        foreach (DataRow row in dt.Rows)
        {
           if(row["Description"].ToString().Contains("User Data"))
           {
               logdata.ID = row["UserID"].ToString();
               logdata.Description = row["Description"].ToString();
           }  

           if (OnDataRetrieved != null)
           {
               OnDataRetrieved(logdata );
           } 
        }
    }
}        

Second class
************
Public class ClsMain
{
    public void ReadData()
    {
        ClsSub sub= new ClsSub();
        sub.LoadData()
    }
}


Main Method
***********
public class Program
{
    static void Main(string[] args)
    {
        ClsMain main= new ClsMain();
        main.OnDataRetrieved += ClsMain_OnDataRetrieved;
        main.ReadData();
        Console.ReadKey();
    }

private static void ClsApplication_OnDataRetrieved(Data log)
{
    Console.WriteLine(log.ID  "\t" log.Description)
}


我需要将在ClsMain类中发布的数据订阅给main方法。如何在main方法中订阅该事件?

1 个答案:

答案 0 :(得分:0)

这可能会解决您的问题:

一个类无法订阅另一个未知的事件。 一个班级也不能订阅一个不存在的事件。

Main创建一个ClsMain的新实例,然后尝试订阅其OnDataRetrieved事件。

    ClsMain main= new ClsMain();
    main.OnDataRetrieved += OnDataRetrieved;
    main.ReadData();
    Console.ReadKey();

最初的问题是ClsMain没有任何此类事件,因此无法订阅它。

ClsSub确实有这样的事件。但是您的应用程序未使用ClsSub的实例。它正在使用ClsMain。它不知道ClsMain创建一个ClsSub的实例,这很好。它不应该知道ClsMain方法内部发生了什么。这样,如果该类的内部发生变化,您的程序仍然可以工作。

因此,为了使您的程序能够预订事件,ClsMain必须拥有这样的事件。它怎么知道什么时候发起活动?创建ClsSub的实例时,可以预订其事件。当该类引发一个事件时,ClsMain依次引发一个自己的事件。

public class ClsMain
{
    public event LogHandler OnDataRetrieved;

    public void ReadData()
    {
        ClsSub sub = new ClsSub();
        sub.OnDataRetrieved += OnDataRetrieved;
        sub.LoadData();
    }
}

现在您的程序只知道ClsMain正在引发一个事件。它不知道也不关心ClsMain在内部如何决定引发该事件。它所知道的都是ClsMain的公共接口,而不是内部的工作方式。知道ClsMain的工作是创建一个ClsSub,订阅其事件,并通过引发自己的事件进行响应。

(我不讨论事件是否是在这种情况下使用的东西-我假设您只是在尝试事件。)


这是我使用过的代码的编辑版本。我只是对其进行了足够的调整,以使其能够编译和运行。 OP中的代码没有GetData方法,因此我添加了一个返回一些伪数据的方法。

public class Data
{
    public string ID { get; set; }
    public string Description { get; set; }
}

public delegate void LogHandler(Data log);

public class ClsSub
{
    public event LogHandler OnDataRetrieved;

    public void LoadData()
    {
        DataTable dt = GetData();

        foreach (DataRow row in dt.Rows)
        {
            Data logdata = new Data();
            logdata.ID = row["UserID"].ToString();
            logdata.Description = row["Description"].ToString();

            if (OnDataRetrieved != null)
            {
                OnDataRetrieved(logdata);
            }
        }
    }

    private DataTable GetData()
    {
        var result = new DataTable();
        result.Columns.Add("UserID", typeof(string));
        result.Columns.Add("Description", typeof(string));
        result.Rows.Add("user1", "description1");
        result.Rows.Add("user2", "description2");
        return result;
    }
}

public class ClsMain
{
    public event LogHandler OnDataRetrieved;

    public void ReadData()
    {
        ClsSub sub = new ClsSub();
        sub.OnDataRetrieved += OnDataRetrieved;
        sub.LoadData();
    }
}

public class Program
{

    static void Main(string[] args)
    {
        ClsMain main = new ClsMain();
        main.OnDataRetrieved += ClsApplication_OnDataRetrieved;
        main.ReadData();
        Console.ReadKey();
    }

    private static void ClsApplication_OnDataRetrieved(Data log)
    {
        Console.WriteLine(log.ID + " " + log.Description);
    }
}

输出为

  

user1 description1
  user2 description2