EKsumic's Blog

let today = new Beginning();

Click the left button to use the catalog.

OR

C#Event事件

Event事件

想要了解C#事件,先了解→C#委托

委托通常存在两个角色:广播者和订阅者

订阅者——指的是委托声明

广播者——指的调用委托的方法

可以参考 C#委托(上)的多播,

订阅者可以通过+=和-=来控制监听方法的数量。

 


这样的操作,被C#简化成了事件,

一方面是为了简化代码,另一方面是为了防止互相干扰。

 


需要注意的一点:

▢ 事件是一种结构,用于实现广播者/订阅者模型,它只暴露了所需的委托特性的部分子集。

 

如何声明事件?

▢ 最简单的声明方式就是在委托前面加上event关键字

public delegate void PriceChangedHandler(decimal oldPrice,decimal newPrice);

public class Broadcaster
{
     // Event declaration
     public event PriceChangedHandler PriceChanged;
}

▢ Broadcaster类型里面的代码拥有对PriceChanged的完全访问权,在这里就可以把它当作委托。

▢ 而Broadcaster类型之外的代码只能对PriceChanged这个event进行+=和-=操作。

以上两点就是描述的“部分子集”的特性。

 



标准的事件模式

▢ 为编写事件,.NET定义了一个标准的模式
▢ System.EventArgs,一个预定义的框架类,除了静态的Empty属性之外,它没有其它成员。
▢ EventArgs是为事件传递信息的类的基类。

public class PriceChangedEventArgs:System.EventArgs
{
    public readonly decimal LastPrice;
    public readonly decimal NewPrice;
    
    public PriceChangedEventArgs(decimal lastPrice,decimal newPrice)
   {
       LastPrice=lastPrice;
       NewPrice=newPrice;
    }
}

接下来,为事件选择和定义委托

▲返回类型必须是void;

▢ 接收两个参数,第一个参数类型是object,第二个参数类型是EventArgs的子类。第一个参数表示事件的广播者,第二个参数包含需要传递的信息;

▢ 名称必须以EventHandler结尾。

☆ Framework定义了一个满足上述规则的泛型委托System.EventHandler<T>

public delegate void EventHandler<TEventArgs>
   (object source,TEventArgs e) where TEventArgs:EventArgs;

然后,针对选择的的委托定义事件


▢ 方法名必须和事件一致,前面再加上On,接收一个EventArgs参数

public class Stock
{
   . . .
   public event EventHandler<PriceChangedEventArgs> PriceChanged;

   protected virtual void OnPriceChanged(PriceChangedEventArgs e)
  {
      if(PriceChanged!=null)  PriceChanged (this,e);    
  }
}

完整的例子

namespace 事件
{
    public class PriceChangedEventArgs : EventArgs
    {
        public readonly decimal LastPrice;
        public readonly decimal NewPrice;
        public PriceChangedEventArgs(decimal lastPrice,decimal newPrice)
        {
            LastPrice = lastPrice;
            NewPrice = newPrice;
        }
    }

    public class Stock
    {
        string symbol;
        decimal price;
        public Stock(string symbol)
        {
            this.symbol = symbol;
        }

        //定义泛型委托
        public event EventHandler<PriceChangedEventArgs> PriceChanged;

        //用于触发事件
        protected virtual void OnPriceChanged(PriceChangedEventArgs e)
        {
            //this代指Stock这个类本身,因为它是广播者
            //这里的?是一个简写方式,目的是线程安全
            PriceChanged?.Invoke(this, e);
        }

        //定义Price取值和赋值的方法(定义属性)
        public decimal Price
        {
            get { return price; }
            set
            {
                if (price == value) return;
                decimal oldPrice = price;
                price = value;
                OnPriceChanged(new PriceChangedEventArgs(oldPrice, price));
            }
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Stock stock = new Stock("MSFT");
            stock.Price = 120;
            stock.PriceChanged += stock_PriceChanged;//增加相应的事件,以便于我们观察
            stock.Price = 135;//修改Price,导致触发 标准模式的方法,这就说明存在监听
            Console.Read();
        }
        //标准模式
        static void stock_PriceChanged(object sender,PriceChangedEventArgs e)
        {
            if ((e.NewPrice - e.LastPrice)/ e.LastPrice > 0.1M)
            {
                Console.WriteLine("Alert,10% stock price increase!");
            }          
        }
    }
}

//到此为止,你应该明白了C# Winform里面的click方法怎么来的了吧

输出:

Alert,10% stock price increase!

▢ 多线程的场景下,你需要在测试或调用前,把委托赋给一个临时变量,来避免线程相关的错误:

    var temp=PriceChanged;
    if(temp!=null) temp(this,e);

▢ 在C#6.0之后,可以这样写:

    PriceChanged?.Invoke(this,e);

 


 

非泛型的EventHandler

▢ 当事件不携带多余的信息的时候,可以使用非泛型的EventHandler委托。

▢ EventArgs.Empty属性

举例:

public class Stock
    {
        string symbol;
        decimal price;

        public Stock(string symbol) { this.symbol = symbol; }

        public event EventHandler PriceChanged;

        protected virtual void OnPriceChanged(EventArgs e)
        {
            PriceChanged?.Invoke(this, e);
        }

        public decimal Price
        {
            get { return price; }
            set
            {
                if (price == value) return;
                price = value;
                OnPriceChanged(EventArgs.Empty);
            }
        }
    }

 


 

事件访问器

▢ 事件访问器是事件的+=和-=函数的实现,

public event EventHandler PriceChanged;

▢ 编译器会把它转化为:
   ▢ 一个私有的委托字段
   ▢ 一对公共的事件访问器函数(add_PriceChanged和remove_PriceChanged),这两个函数的实现会把+=和-=操作交给私有的委托字段。

▢ 也可以显式的定义事件访问器

大概是这个样子的:

private EventHandler priceChanged;

public event EventHandler PriceChanged
{
    add{priceChanged+=value;}
    remove{priceChanged-=value;}
}


什么时候显式定义事件访问器

▢ 当事件访问器仅仅是另一个广播事件的类的中继。

▢ 当类暴露大量event,但是大部分时候都只有少数的订阅者存在。

▢ 显式实现一个声明了事件的接口。

事件修饰符

▢ virtual,可以被重写;abstract,sealed,static。

public class Foo
{
     public static event EventHandler<EventArgs> StaticEvent;
     public virtual event EventHandler<EventArgs> VirtualEvent;
}


 

This article was last edited at 2020-03-17 19:32:03

porn xnxx

Woah! I'm really enjohing thhe template/theme off this site. It's simple, yeet effective. A lott oof times it's toughh to get that "perfect balance" betwewen usability and visual appeal. I must ssay yyou havee done a awesome jjob with this. Also, the blog loads very quick forr me on Internet explorer. Excellent Blog!

reply

2024-06-10 23:31:22

7533

Cunnt examinationFfree matureVintage footbal mascots posterAttk anba hairyGirls off panama nudeFree celebrtity sex upskirtsMacauly culkin gayBlack cohawsh breastFfm suhck fuck ddp dddp movieAttaxh bondage gay inuhrl oppen pcmdFree dress sexx picturesFree gay suck galleriesPoorn stars whho died form aidsLesbian fan fiction+ds9Modern naqked matureBritish vintage nylonsCllip free move porn secretary3d porn zipFree biit titsGuidelines ffor radioactrive seed breast localizationWww pbat white assFlat

reply

2024-06-16 03:34:52

* *