Чи має .NET вбудований EventArgs <T>?


84

Я готуюсь створити загальний клас EventArgs для аргументів подій, що містять один аргумент:

public class EventArg<T> : EventArgs
{
    // Property variable
    private readonly T p_EventData;

    // Constructor
    public EventArg(T data)
    {
        p_EventData = data;
    }

    // Property for EventArgs argument
    public T Data
    {
        get { return p_EventData; }
    }
}

Перш ніж це зробити, чи має C # ту саму функцію, вбудовану в мову? Здається, я згадую щось подібне, коли вийшов C # 2.0, але зараз я не можу його знайти.

Або, кажучи по-іншому, чи повинен я створювати свій власний загальний клас EventArgs, або C # пропонує такий? Спасибі за вашу допомогу.


9
Ви, можливо, бачилиEventhandler<T>
Хенка Холтермана

1
Можливо, ви бачили EventArgs<T>в коді на основі CAB / SCSF. Це досить часто зустрічається в додатках CAB / SCSF. Хоча це не входить в рамки, то є Об'єкт EventArgs <T> реалізація.
Шон Вільсон

Відповіді:


66

Ні. Ви, напевно, думали про це EventHandler<T>, що дозволяє визначити делегата для будь-якого конкретного типу EventArgs.

Я особисто не вважаю, що EventArgs<T>це настільки добре, як підгонка. Інформація, що використовується як "корисне навантаження" у аргументах подій, на мій погляд, повинна бути спеціальним класом, щоб зробити її використання та очікувані властивості дуже зрозумілими. Використання загального класу запобіжить вам можливість розміщувати значущі імена на своїх місцях. (Що означає "Дані"?)


50
У орієнтованих на дані програмах, схожих на MPI, досить часто можна побачити EventArgs <T> на місці для обробки даних, щоб розробники могли використовувати вбудовану безпечну систему підписки / реєстрації (.NET Events and Delegates), оскільки абсолютно немає сенсу створювати підкласи EventArgs лише для транспортування даних. Якщо ви маєте намір транспортувати дані, можливо, має сенс більше визначити EventArgs <T>, який ви можете підкласувати для дискретного використання БЕЗ врахування даних, що транспортуються. TL: DR Ця перша частина цієї відповіді є фактичною та точною, друга частина - суб’єктивною / думкою.
Шон Вільсон

1
Я гадаю, ти маєш рацію ... противись ліні, яка привела мене сюди. Це як коли ледачі розробники використовують Tuple <,>. Страшні речі.
CRice

Хороший момент, але це, по суті, буде робити те саме, що і Microsoft, коли вони додавали властивість Tag до класів Controls. Звичайно, просто coz 'MS зробив це, не робить це правильно.
Кен Річардс,

1
Я згоден з першим коментатором, вся друга половина цієї відповіді - це суб'єктивна думка / кодекс-релігія, яка не була конструктивною. :(
BrainSlugs83

5
Як EventHandler <Customer> або EventHandler <Order> передають менше інформації, ніж CustomerEventHandler або OrderEventHandler ?
Кварклі

33

Треба сказати, що я не розумію всіх "пуристів" тут. тобто якщо у вас вже визначений клас пакета - який має всі особливості, властивості тощо - чому хак створює один зайвий непотрібний клас просто для того, щоб мати можливість слідувати за механізмом подій / аргументів, стилем підпису? річ у тому, що - не все, що є у .NET - або, з цього приводу, «відсутнє» - це «добре» - МС роками «виправляється» ... Я б сказав, просто піди і створіть - як я це зробив - бо мені це було потрібно просто так - і це заощадило мені багато часу,


3
У цьому випадку суть "пуристів" полягає в тому, щоб якомога чіткіше пояснити намір. У виробничій програмі я маю десятки цих класів EventArgs. Через рік буде легше зрозуміти, що я зробив, якщо дотримуватимусь порад Ріда і створити власний клас EventArgs.
Девід Вінеман

9
не мав на увазі мітити кого-небудь :) суть у випадку “загальний” - якщо вам потрібен лише десяток різних подій, добре. Але якщо ви заздалегідь не знаєте природи Т - це відомо лише під час виконання - ну, вам начебто потрібна загальна подія. Отже, якщо у вас є програма, яка в значній мірі стосується загальних препаратів, довільна кількість типів, невідомих - тоді вам також потрібні загальні події. або тобто не існує чіткого рішення для кожної проблеми, правило великого пальця - це просто правило - і це я мав на увазі під пуристами, кожне рішення різне, вам потрібно зважити речі, плюси і мінуси
NSGaga-в основному- неактивний

2
Дизайн не є чорно-білим, тому я, як правило, погоджуюся з NSGaga тут. Іноді доречно "швидко і брудно". Мова повинна бути багатофункціональною, щоб відповідати більшості випадків використання. Розробник повинен вирішити, що підходить. Востаннє MS намагалися змусити "хороший" дизайн, обмежуючи мову, WPF, коли вони намагалися змусити використовувати XAML, суворо обмежуючи .NET API, і це було жахливо.
Robear,

9

Він існує. Принаймні, це відбувається зараз.

Ви можете знайти DataEventArgs<TData>деякі різні збірки / простори імен Microsoft, наприклад Microsoft.Practices.Prism.Events . Однак це простори імен, які, можливо, вам не вдасться включити у свій проект, тому ви можете просто використовувати власну реалізацію.


Я намагався знайти рекомендації та міркування щодо того, коли і навіщо використовувати такий загальний клас EventArgs. Дивіться також: stackoverflow.com/questions/15766219 / ...
Ulf Åkerstedt

Ось деякі аспекти , остерігайтеся при ухваленні рішення про використання родового EventArgs: stackoverflow.com/questions/129453 / ...
Ulf Åkerstedt

7

Якщо ви вирішите не використовувати Prism , але все ж хочете спробувати загальний підхід EventArgs .

public class GenericEventArgs<T> : EventArgs
{
    public T EventData { get; private set; }

    public GenericEventArgs(T EventData)
    {
        this.EventData = EventData;
    }
}

// Використовуйте наступний зразок коду для оголошення події ObjAdded

public event EventHandler<GenericEventArgs<TargetObjType>> ObjAdded;

// Використовуйте наступний зразок коду, щоб викликати подію ObjAdded

private void OnObjAdded(TargetObjType TargetObj)
{
    if (ObjAdded!= null)
    {
        ObjAdded.Invoke(this, new GenericEventArgs<TargetObjType>(TargetObj));
    }
}

// І нарешті, ви можете підписатися на вашу подію ObjAdded

SubscriberObj.ObjAdded +=  (object sender, GenericEventArgs<TargetObjType> e) =>
{
    // Here you can explore your e.EventData properties
};

3

НЕ ВСТУПЛЕНО ЗАГАЛЬНИХ АРГУМІВ. Якщо ви будете слідувати Microsoft EventHandler шаблон, то ви реалізуєте ваші отримані EventArgs , як ви запропонували: public class MyStringChangedEventArgs : EventArgs { public string OldValue { get; set; } }.

ОДНАЧ - якщо ваш посібник зі стилю команди приймає спрощення - ваш проект може використовувати легкі події, наприклад:

public event Action<object, string> MyStringChanged;

використання:

// How to rise
private void OnMyStringChanged(string e)
{
    Action<object, string> handler = MyStringChanged;    // thread safeness
    if (handler != null)
    {
        handler(this, e);
    }
}

// How to handle
myObject.MyStringChanged += (sender, e) => Console.WriteLine(e);

Зазвичай проекти PoC використовують останній підхід. Однак у професійних заявниках слід пам’ятати про обґрунтування поліцейських валют # CA1009: https://msdn.microsoft.com/en-us/library/ms182133.aspx


1

Проблема із загальним типом полягає в тому, що навіть якщо DerivedType успадковує від BaseType, EventArgs (DerivedType) не успадковує від EventArgs (BaseType). Таким чином, використання EventArgs (BaseType) запобігає подальшому використанню похідної версії типу.


2
Це явно неправда. див. "Коваріація та контраваріантність у дженериках - Microsoft.com" msdn.microsoft.com/en-us/library/dd799517.aspx
Шон Вільсон

1
@ShaunWilson: Який аспект є хибним? Можна було б визначити коваріантний інтерфейс IEventArgs, але єдиними класами, які можуть бути загальними щодо параметрів загального типу, є делегати, на які не буде подано Delegate.Combine. Делегати, з якими буде використовуватися, Delegate.Combineне повинні бути коваріантними, оскільки можна зберігати, наприкладAction<DerivedType> у поле типу Action<BaseType>, але пізніша спроба до Combineцього з екземпляром Action<BaseType>буде невдалою.
supercat

-4

Причина цього не полягає в тому, що в кінцевому підсумку це відбувається, це ви реалізуєте це, і тоді, коли ви йдете заповнювати T, ви повинні створити клас із сильно набраними однозначними властивостями, який виступає в якості пакета даних для вашого аргументу події, на півдорозі впровадження ви розумієте, що немає жодної причини, чому ви не просто змушуєте цей клас успадковуватись від EventArgs і називаєте це хорошим.

Якщо ви просто не хочете рядок або щось подібне до базового для вашого пакету даних, в цьому випадку, ймовірно, існують класи EventArgs, стандартні в .NET, які призначені для задоволення будь-якої простої мети, з якою ви досягаєте.


-1. Я маю ТОЧНО цю ситуацію зараз, і моє корисне навантаження буде незмінним об'єктом, який є "повідомленням", що надходить з автобуса ... і знаходиться в інших місцях теж. Спеціальний EventArgs .... створює тут надлишковий клас. Незвично, але додаток такий.
TomTom
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.