Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/261.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 代表和活动之间有什么区别?_C#_Events_Delegates_Glossary - Fatal编程技术网

C# 代表和活动之间有什么区别?

C# 代表和活动之间有什么区别?,c#,events,delegates,glossary,C#,Events,Delegates,Glossary,代表和活动之间有什么区别?这两个函数是否都包含对可以执行的函数的引用?一个事件声明在委托实例上添加了一层抽象和保护。此保护可防止委托的客户端重置委托及其调用列表,并且仅允许从调用列表中添加或删除目标。除了语法和操作属性之外,还有语义差异 从概念上讲,委托是功能模板;也就是说,它们表示一个函数必须遵守的契约,才能被视为委托的“类型” private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { Media

代表和活动之间有什么区别?这两个函数是否都包含对可以执行的函数的引用?

一个事件声明在委托实例上添加了一层抽象和保护。此保护可防止委托的客户端重置委托及其调用列表,并且仅允许从调用列表中添加或删除目标。

除了语法和操作属性之外,还有语义差异

从概念上讲,委托是功能模板;也就是说,它们表示一个函数必须遵守的契约,才能被视为委托的“类型”

private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    Mediator.OnPersonChanged((Person)comboBox1.SelectedItem); //Call the mediator's OnPersonChanged method. This will in turn call all the methods assigned (i.e. subscribed to) to the delegate -- in this case `DetailView_PersonChanged`.
}
事件代表。。。嗯,事件。它们用于在发生事件时提醒某人,是的,它们遵守委托定义,但它们不是同一件事


即使它们是完全相同的东西(语法上和IL代码中),仍然会存在语义上的差异。一般来说,我更喜欢为两个不同的概念使用两个不同的名称,即使它们是以相同的方式实现的(这并不意味着我喜欢使用相同的代码两次)。

您也可以在接口声明中使用事件,而不是委托。

在.net中的事件是Add方法和Remove方法的指定组合,两者都需要某种特定类型的委托。C#和vb.net都可以为add和remove方法自动生成代码,这些方法将定义一个用于保存事件订阅的委托,并向该订阅委托添加/删除传入的delegate。当且仅当订阅列表非空时,VB.net还将自动生成代码(使用RaiseEvent语句)来调用订阅列表;出于某种原因,C#不会生成后者


请注意,虽然使用多播委托管理事件订阅很常见,但这并不是唯一的方法。从公共角度来看,潜在的事件订阅者需要知道如何让对象知道它想要接收事件,但不需要知道发布者将使用什么机制来引发事件。还要注意的是,尽管在.net中定义事件数据结构的人显然认为应该有一种公开的方法来提高它们,但C#和vb.net都没有利用该功能。

这里是另一个很好的链接。

简而言之,文章中的事件是对委托的封装

引自文章:

假设事件在C#/.NET中不作为一个概念存在。另一个类如何订阅事件?三种选择:

  • 公共委托变量

  • 由属性支持的委托变量

  • 具有AddXXXHandler和RemoveXXXHandler方法的委托变量

  • 选择1显然是可怕的,因为我们厌恶公共变量的所有正常原因

    选项2稍微好一点,但允许订阅者有效地相互覆盖-编写someInstance.MyEvent=eventHandler太容易了;它将替换任何现有的事件处理程序,而不是添加新的事件处理程序。此外,还需要编写属性

    选项3基本上是事件提供给您的内容,但是有一个保证约定(由编译器生成并由IL中的额外标志支持)和一个“免费”实现,如果您对类字段事件提供的语义感到满意的话。订阅和取消订阅事件是封装的,不允许任意访问事件处理程序列表,语言可以通过为声明和订阅提供语法使事情变得更简单


    要了解这些差异,您可以看看这两个示例

    委托示例(在本例中,是一个操作,它是一种不返回值的委托)

    要使用委托,应执行以下操作:

    Animal animal= new Animal();
    animal.Run += () => Console.WriteLine("I'm running");
    animal.Run += () => Console.WriteLine("I'm still running") ;
    animal.RaiseEvent();
    
    此代码运行良好,但可能存在一些弱点

    例如,如果我这样写:

    animal.Run += () => Console.WriteLine("I'm running");
    animal.Run += () => Console.WriteLine("I'm still running");
    animal.Run = () => Console.WriteLine("I'm sleeping") ;
    
    在最后一行代码中,我覆盖了前面的行为,只丢失了一个
    +
    (我使用了
    =
    而不是
    +=

    另一个弱点是使用
    Animal
    类的每个类都可以直接调用委托。例如,
    animal.Run()
    animal.Run.Invoke()
    在动物类之外有效

    为了避免这些弱点,可以在c#中使用
    事件

    您的动物等级将以以下方式更改:

    public class ArgsSpecial : EventArgs
    {
        public ArgsSpecial (string val)
        {
            Operation=val;
        }
    
        public string Operation {get; set;}
    } 
    
    public class Animal
    {
        // Empty delegate. In this way you are sure that value is always != null 
        // because no one outside of the class can change it.
        public event EventHandler<ArgsSpecial> Run = delegate{} 
            
        public void RaiseEvent()
        {  
             Run(this, new ArgsSpecial("Run faster"));
        }
    }
    
    差异:

  • 您使用的不是公共属性,而是公共字段(使用事件,编译器会保护您的字段不受不必要的访问)
  • 无法直接分配事件。在本例中,它不会导致我之前通过重写行为显示的错误
  • 类之外的任何人都不能引发或调用该事件。例如,
    animal.Run()
    animal.Run.Invoke()
    在animal类之外无效,并将产生编译器错误
  • 事件可以包含在接口声明中,而字段不能
  • 注:

    EventHandler声明为以下委托:

    public delegate void EventHandler (object sender, EventArgs e)
    
    它接受发送方(对象类型)和事件参数。如果发送方来自静态方法,则该发送方为null


    这个例子使用了
    EventHandler来记录EventHandler

    事件和委托之间的巨大误解!!!委托指定一种类型(例如
    ,或
    接口
    ),而事件只是一种成员(例如字段、属性等)。而且,就像任何其他类型的成员一样,事件也有一个类型。但是,对于事件,事件的类型必须由委托指定。例如,不能声明由接口定义的类型的事件

    最后,我们可以使
    public delegate void EventHandler (object sender, EventArgs e)
    
    class Mediator
    {
        public delegate void PersonChangedDelegate(Person p); //delegate type definition
        public static PersonChangedDelegate PersonChangedDel; //delegate instance. Detail view will "subscribe" to this.
        public static void OnPersonChanged(Person p) //Form1 will call this when the drop-down changes.
        {
            if (PersonChangedDel != null)
            {
                PersonChangedDel(p);
            }
        }
    }
    
    public partial class DetailView : UserControl
    {
        public DetailView()
        {
            InitializeComponent();
            Mediator.PersonChangedDel += DetailView_PersonChanged;
        }
    
        void DetailView_PersonChanged(Person p)
        {
            BindData(p);
        }
    
        public void BindData(Person p)
        {
            lblPersonHairColor.Text = p.HairColor;
            lblPersonId.Text = p.IdPerson.ToString();
            lblPersonName.Text = p.Name;
            lblPersonNickName.Text = p.NickName;
    
        }
    }
    
    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        Mediator.OnPersonChanged((Person)comboBox1.SelectedItem); //Call the mediator's OnPersonChanged method. This will in turn call all the methods assigned (i.e. subscribed to) to the delegate -- in this case `DetailView_PersonChanged`.
    }
    
    class Mediator
    {
    
        private static readonly Mediator _Instance = new Mediator();
    
        private Mediator() { }
    
        public static Mediator GetInstance()
        {
            return _Instance;
        }
    
        public event EventHandler<PersonChangedEventArgs> PersonChanged; //this is just a property we expose to add items to the delegate.
    
        public void OnPersonChanged(object sender, Person p)
        {
            var personChangedDelegate = PersonChanged as EventHandler<PersonChangedEventArgs>;
            if (personChangedDelegate != null)
            {
                personChangedDelegate(sender, new PersonChangedEventArgs() { Person = p });
            }
        }
    }
    
    public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
    
    public partial class DetailView : UserControl
    {
        public DetailView()
        {
            InitializeComponent();
            Mediator.GetInstance().PersonChanged += DetailView_PersonChanged;
        }
    
        void DetailView_PersonChanged(object sender, PersonChangedEventArgs e)
        {
            BindData(e.Person);
        }
    
        public void BindData(Person p)
        {
            lblPersonHairColor.Text = p.HairColor;
            lblPersonId.Text = p.IdPerson.ToString();
            lblPersonName.Text = p.Name;
            lblPersonNickName.Text = p.NickName;
    
        }
    }
    
    private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
            Mediator.GetInstance().OnPersonChanged(this, (Person)comboBox1.SelectedItem);
    }
    
    class PersonChangedEventArgs
    {
        public Person Person { get; set; }
    }
    
     /*
    This is working program in Visual Studio.  It is not running in fiddler because of infinite loop in code.
    This code demonstrates the difference between event and delegate
            Event is an delegate reference with two restrictions for increased protection
    
                1. Cannot be invoked directly
                2. Cannot assign value to delegate reference directly
    
    Toggle between Event vs Delegate in the code by commenting/un commenting the relevant lines
    */
    
    public class RoomTemperatureController
    {
        private int _roomTemperature = 25;//Default/Starting room Temperature
        private bool _isAirConditionTurnedOn = false;//Default AC is Off
        private bool _isHeatTurnedOn = false;//Default Heat is Off
        private bool _tempSimulator = false;
        public  delegate void OnRoomTemperatureChange(int roomTemperature); //OnRoomTemperatureChange is a type of Delegate (Check next line for proof)
        // public  OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above), 
        public  event OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above), 
    
        public RoomTemperatureController()
        {
            WhenRoomTemperatureChange += InternalRoomTemperatuerHandler;
        }
        private void InternalRoomTemperatuerHandler(int roomTemp)
        {
            System.Console.WriteLine("Internal Room Temperature Handler - Mandatory to handle/ Should not be removed by external consumer of ths class: Note, if it is delegate this can be removed, if event cannot be removed");
        }
    
        //User cannot directly asign values to delegate (e.g. roomTempControllerObj.OnRoomTemperatureChange = delegateMethod (System will throw error)
        public bool TurnRoomTeperatureSimulator
        {
            set
            {
                _tempSimulator = value;
                if (value)
                {
                    SimulateRoomTemperature(); //Turn on Simulator              
                }
            }
            get { return _tempSimulator; }
        }
        public void TurnAirCondition(bool val)
        {
            _isAirConditionTurnedOn = val;
            _isHeatTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
            System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
            System.Console.WriteLine("Heat :" + _isHeatTurnedOn);
    
        }
        public void TurnHeat(bool val)
        {
            _isHeatTurnedOn = val;
            _isAirConditionTurnedOn = !val;//Binary switch If Heat is ON - AC will turned off automatically (binary)
            System.Console.WriteLine("Aircondition :" + _isAirConditionTurnedOn);
            System.Console.WriteLine("Heat :" + _isHeatTurnedOn);
    
        }
    
        public async void SimulateRoomTemperature()
        {
            while (_tempSimulator)
            {
                if (_isAirConditionTurnedOn)
                    _roomTemperature--;//Decrease Room Temperature if AC is turned On
                if (_isHeatTurnedOn)
                    _roomTemperature++;//Decrease Room Temperature if AC is turned On
                System.Console.WriteLine("Temperature :" + _roomTemperature);
                if (WhenRoomTemperatureChange != null)
                    WhenRoomTemperatureChange(_roomTemperature);
                System.Threading.Thread.Sleep(500);//Every second Temperature changes based on AC/Heat Status
            }
        }
    
    }
    
    public class MySweetHome
    {
        RoomTemperatureController roomController = null;
        public MySweetHome()
        {
            roomController = new RoomTemperatureController();
            roomController.WhenRoomTemperatureChange += TurnHeatOrACBasedOnTemp;
            //roomController.WhenRoomTemperatureChange = null; //Setting NULL to delegate reference is possible where as for Event it is not possible.
            //roomController.WhenRoomTemperatureChange.DynamicInvoke();//Dynamic Invoke is possible for Delgate and not possible with Event
            roomController.SimulateRoomTemperature();
            System.Threading.Thread.Sleep(5000);
            roomController.TurnAirCondition (true);
            roomController.TurnRoomTeperatureSimulator = true;
    
        }
        public void TurnHeatOrACBasedOnTemp(int temp)
        {
            if (temp >= 30)
                roomController.TurnAirCondition(true);
            if (temp <= 15)
                roomController.TurnHeat(true);
    
        }
        public static void Main(string []args)
        {
            MySweetHome home = new MySweetHome();
        }
    
    
    }
    
    // eventTest.SomeoneSay = null;              // Compile Error.
    // eventTest.SomeoneSay = new Say(SayHello); // Compile Error.
    
    public class DelegateTest
    {
        public delegate void Say(); // Define a pointer type "void <- ()" named "Say".
        private Say say;
    
        public DelegateTest() {
            say  = new Say(SayHello);     // Setup the field, Say say, first.
            say += new Say(SayGoodBye);
            
            say.Invoke();
        }
        
        public void SayHello() { /* display "Hello World!" to your GUI. */ }
        public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
    }
    
    public class EventTest
    {
        public delegate void Say();
        public event Say SomeoneSay;  // Use the type "Say" to define event, an 
                                      // auto-setup-everything-good field for you.
        public EventTest() {
             SomeoneSay += SayHello;
             SomeoneSay += SayGoodBye;
    
             SomeoneSay();
        }
        
        public void SayHello() { /* display "Hello World!" to your GUI. */ }
        public void SayGoodBye() { /* display "Good bye!" to your GUI. */ }
    }