【问题标题】:Creating own Event for initialization of an object为对象的初始化创建自己的事件
【发布时间】:2014-02-09 09:40:23
【问题描述】:

所以我试图创建自己的事件来初始化一个名为 Car 的类,该类继承自汽车对象。以下是 C# 代码中的相同内容:

`

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Abc.Training.Artifacts;

namespace Abc.Training.Objects
{
    public abstract class Automobile
    {
        public string Model { get; set; }
        public string Manufacturer { get; set; }
        public string YoM { get; set; }
    }

    public class Car : Automobile 
    {
        public static event Delegates.ObjectInitHandler OnInit;

        public string MarketSegment { get; set; }
        public int BootSpace { get; set; } 

        public Car(string model, string manufacturer, string yom)
        {
            Model = model ;
            Manufacturer = manufacturer;
            YoM = yom;
            ObjectInitEventArgs eArgs = new ObjectInitEventArgs();
            eArgs.IsResidentObject = true;
            eArgs.ObjectType = this.GetType();
            if (OnInit != null) OnInit(this, eArgs);
        }

    }
}

`

ObjectInitHandler 及其参数(这里使用的委托类型)也是由我创建的:

`

public delegate void ObjectInitHandler(object sender, ObjectInitEventArgs e);
 public class ObjectInitEventArgs:EventArgs
    {
        public Type ObjectType { get; set; }
        public bool IsResidentObject { get; set; }
    }

`

我正在订阅以下活动:

`

Car.OnInit += new Delegates.ObjectInitHandler(Car_OnInit);//able to do this as event is static
Car c = new Car("Maruti", "Maruti", "2004");
void Car_OnInit(object sender, ObjectInitEventArgs e)
{
   Console.WriteLine("Car object initialized");
}

`

我想为这个类创建一个事件 OnInit。但是,如果我在发布者(我的 Car 类)中放置一个实例事件 OnInit,我必须先初始化该类,然后才能订阅此事件。因为我想在初始化时触发这个事件,所以这对我来说是一个先有鸡还是先有蛋的问题。

我通过创建一个静态事件对象并在对象初始化之前进行订阅来解决它,如下所示(这是来自上面代码本身的sn-p):

public static event Delegates.ObjectInitHandler OnInit;

但是,在 ASP.NET 应用程序中,这意味着如果多个用户访问此应用程序,我将拥有相同的委托对象,该对象将具有重复的事件订阅(因为它是静态的),这显然不是很酷。

是否有我可以遵循的设计模式将事件也作为实例成员,但我仍然可以在实例化之前订阅事件?

【问题讨论】:

    标签: c# asp.net .net c#-4.0 c#-3.0


    【解决方案1】:

    我认为你必须将该函数作为回调传递:

    public class Car : Automobile 
        {
          // public static event Delegates.ObjectInitHandler OnInit; remove this
    
            public string MarketSegment { get; set; }
            public int BootSpace { get; set; } 
    
            public Car(string model, string manufacturer, string yom,ObjectInitHandler OnInit) //add the callback as parameter.
            {
                Model = model ;
                Manufacturer = manufacturer;
                YoM = yom;
                ObjectInitEventArgs eArgs = new ObjectInitEventArgs();
                eArgs.IsResidentObject = true;
                eArgs.ObjectType = this.GetType();
                if (OnInit != null) OnInit(this, eArgs);
            }
    
        }
    

    在初始化对象时向构造函数传递回调:

    Car c = new Car("Maruti", "Maruti", "2004",new Delegates.ObjectInitHandler(Car_OnInit));
    void Car_OnInit(object sender, ObjectInitEventArgs e)
    {
       Console.WriteLine("Car object initialized");
    }
    

    实际上,我认为您的代码中不需要初始化事件,除非您的构造函数中有异步操作

    【讨论】:

    • 需要:示例 - 页面谎言周期中的 Page_Init 事件
    • @Gaurav Karwal:Page_Init 是不同的情况。基类定义了这一点并在派生类中被覆盖。
    【解决方案2】:

    这是一种方法,它不使用静态,我使用动作而不是事件参数。 (您可以按照自己的方式使用它!)
    请注意,我在创建时将回调函数传递给了对象!

    class Program
    {
        static void Main(string[] args)
        {
            Car c = new Car("Maruti", "Maruti", "2004", Car_OnInit);
    
            Console.WriteLine("Press a key to exit...");
            Console.ReadKey();
        }
        static void Car_OnInit()
        {
            Console.WriteLine("Car object initialized");
        }
    
    }
    public abstract class Automobile
    {
        public string Model { get; set; }
        public string Manufacturer { get; set; }
        public string YoM { get; set; }
    }
    
    public class Car : Automobile
    {
        public event Action OnInit;
    
        public string MarketSegment { get; set; }
        public int BootSpace { get; set; }
    
        public Car(string model, string manufacturer, string yom, Action callBack)
        {
            this.OnInit += callBack;
            Model = model;
            Manufacturer = manufacturer;
            YoM = yom;
            if (OnInit != null) OnInit();
        }
    
    }
    

    如果您愿意,您也可以传递任何参数,只需使用 Action<T>(如 Action<string>)代替 Action。那么你的回调将是 Car_OnInit(string)

    【讨论】:

    • 我假设您想在创建实例之前向实例添加多个事件处理程序!在这种情况下,您应该将回调收集在一个数组(Action[] callBackArray)中,将其传递给您的新车,然后在构造函数中,将所有回调添加到您的事件中。这样在构造函数结束时,事件会调用所有之前分配的函数...
    【解决方案3】:

    没有必要(即使有可能)。您拥有所需的一切。

    首先,您不会订阅每个页面加载/每个用户的事件。你会做一次......例如Application_Start

    第二..您拥有活动所需的一切。注意这行代码:

    if (OnInit != null) OnInit(this, eArgs);
    

    您将this 作为sender 参数传递。 thisCar 的一个实例。所以,在你的事件中......你有你关心的实例:

    void Car_OnInit(object sender, ObjectInitEventArgs e) {
        var instance = sender as Car;
    
        // use instance here.
    }
    

    【讨论】:

    • 首先,您不会订阅每个页面加载/每个用户的事件。 - 我当然会,例如 Page_Init 事件做同样的事情。 car 对象仅用于演示,我需要在初始化时了解许多对象。
    猜你喜欢
    • 2015-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-20
    • 2019-07-15
    • 2011-11-18
    • 1970-01-01
    相关资源
    最近更新 更多