ইভেন্ট অ্যাকশন <> বনাম ইভেন্ট ইভেন্টহ্যান্ডলার <>


144

ঘোষণা event Action<>এবং এর মধ্যে কি আলাদা আছে event EventHandler<>?

ধরে নিচ্ছি যে কোনও বস্তু আসলে কী ঘটনা উত্থাপন করেছে তা বিবেচ্য নয়।

উদাহরণ স্বরূপ:

public event Action<bool, int, Blah> DiagnosticsEvent;

বনাম

public event EventHandler<DiagnosticsArgs> DiagnosticsEvent;

class DiagnosticsArgs : EventArgs
{
    public DiagnosticsArgs(bool b, int i, Blah bl)
    {...}
    ...
}

উভয় ক্ষেত্রে ব্যবহার প্রায় একই হবে:

obj.DiagnosticsEvent += HandleDiagnosticsEvent;

event EventHandler<>প্যাটার্ন সম্পর্কে আমি পছন্দ করি না এমন বেশ কয়েকটি জিনিস রয়েছে :

  • ইভেন্টআর্গস থেকে প্রাপ্ত অতিরিক্ত ধরণের ঘোষণা
  • অবজেক্ট উত্স বাধ্যতামূলক পাসিং - প্রায়শই কেউ যত্ন করে না

আরও কোড কোনও স্পষ্ট সুবিধা ছাড়াই বজায় রাখার জন্য আরও কোড বোঝায়।

ফলস্বরূপ, আমি পছন্দ করি event Action<>

তবে কেবলমাত্র অ্যাকশন <> এ অনেক ধরণের আর্গুমেন্ট থাকলে কেবলমাত্র একটি অতিরিক্ত শ্রেণি প্রয়োজন।


2
প্লাসওন (আমি কেবল সিস্টেমটিকে পরাজিত করেছি) "কারও পরোয়া নেই"
হায়ানকভ

@ প্লাসওন: আমার আসলে প্রেরককে জানতে হবে! কিছু ঘটবে বলুন এবং আপনি এটি জানতে চেয়েছিলেন কে এটি করেছে। এটাই আপনার দরকার 'অবজেক্ট সোর্স' (ওরফে প্রেরক)।
কামরান বিগডেলি

প্রেরক ইভেন্টের
পেডে

উত্তর:


67

মূল পার্থক্যটি হ'ল আপনি যদি Action<>আপনার ইভেন্টটি ব্যবহার করেন তবে এটি সিস্টেমে কার্যত অন্য কোনও ইভেন্টের নকশার ধরণটি অনুসরণ করবে না, যা আমি একটি অসুবিধা বিবেচনা করব।

প্রভাবশালী ডিজাইনের প্যাটার্নের সাথে একটি উল্টো দিক (একইরূপ শক্তি ছাড়া) আপনি EventArgsইভেন্টটির স্বাক্ষর পরিবর্তন না করেই নতুন বৈশিষ্ট্য সহ অবজেক্টটি প্রসারিত করতে পারেন । আপনি যদি ব্যবহার করেন তবে এটি এখনও সম্ভব হবে Action<SomeClassWithProperties>, তবে আমি সেই ক্ষেত্রে নিয়মিত পন্থাটি ব্যবহার না করে সত্যিই বিষয়টিটি দেখতে পাচ্ছি না।


Action<>মেমরি ফাঁস ফলাফল ব্যবহার করতে পারে? EventHandlerডিজাইনের প্যাটার্নটির একটি নেতিবাচকতা হ'ল মেমরি ফুটো। এছাড়াও এটি উল্লেখ করা উচিত যে একাধিক ইভেন্ট হ্যান্ডলার থাকতে পারে তবে কেবলমাত্র একটি অ্যাকশন রয়েছে
লূক টি ওব্রায়েন

4
@ LukeTO'Brien: ইভেন্ট, সারাংশ প্রতিনিধিদের মধ্যে তাই একই মেমরি লিক সম্ভাবনার সঙ্গে অস্তিত্ব Action<T>। এছাড়াও, একটি বিভিন্ন পদ্ধতি উল্লেখ Action<T> করতে পারে। এখানে এমন একটি গিস্ট
ফ্রেড্রিক মের্ক

88

পূর্ববর্তী কয়েকটি উত্তরের উপর ভিত্তি করে আমি আমার উত্তরটি তিনটি ভাগে বিভক্ত করতে যাচ্ছি।

প্রথমত, Action<T1, T2, T2... >বিকাশযুক্ত শ্রেণীর ব্যবহার করে বনাম ব্যবহারের শারীরিক সীমাবদ্ধতা EventArgs। তিনটি রয়েছে: প্রথমত, আপনি যদি পরামিতিগুলির সংখ্যা বা প্রকারগুলি পরিবর্তন করেন তবে প্রতিটি প্যাটার্নে সাবস্ক্রাইব করা নতুন প্যাটার্নায় মেনে চলতে হবে। যদি এটি জনসাধারণের মুখোমুখি ইভেন্ট হয় যা তৃতীয় পক্ষের অ্যাসেমব্লিগুলি ব্যবহার করবে এবং ইভেন্টের আর্গোসগুলি পরিবর্তিত হওয়ার কোনও সম্ভাবনা রয়েছে, তবে এটি ধারাবাহিকতার জন্য ইভেন্ট আরগগুলি থেকে প্রাপ্ত একটি কাস্টম শ্রেণি ব্যবহার করার কারণ হবে (মনে রাখবেন, আপনি এখনও থাকতে পারেন) একটি ব্যবহার Action<MyCustomClass>) দ্বিতীয়ত, ব্যবহার Action<T1, T2, T2... >যদি না আপনি একটি কিছু (উদাহরণস্বরূপ, এটি একটি পরিচালিত সম্পত্তি সঙ্গে বস্তুর ধরনের আছে কলিং পদ্ধতি এ প্রতিক্রিয়া ফিরে পাশ করতে প্রতিরোধ করা হবে) এই ক্রিয়াটি সহ পাস করা হয়েছে। তৃতীয়ত, আপনি নামকরণের প্যারামিটারগুলি পান না, সুতরাং আপনি যদি 3 boolএর int, দুটি পার করছেনstringএর এবং ক DateTime, এই মানগুলির অর্থ কী তা আপনার কোনও ধারণা নেই। পার্শ্ব নোট হিসাবে, আপনার এখনও "ব্যবহারের সময় নিরাপদে এই ইভেন্টটি ফায়ার করুন Action<T1, T2, T2... >" থাকতে পারে।

দ্বিতীয়ত, ধারাবাহিকতা জড়িত। আপনার যদি ইতিমধ্যে একটি বৃহত সিস্টেমের সাথে কাজ করা থাকে তবে আপনার খুব ভাল কারণ না থাকলে আপনার সিস্টেমের বাকি অংশটি যেভাবে ডিজাইন করা হয়েছে তা অনুসরণ করা প্রায় ভাল better আপনার যদি প্রকাশ্যে এমন ইভেন্টগুলির মুখোমুখি হয় যা বজায় রাখা দরকার, উদ্ভূত শ্রেণীর বিকল্পের ক্ষমতাটি গুরুত্বপূর্ণ হতে পারে। মন যে রাখতে.

তৃতীয়ত, বাস্তব জীবনের অনুশীলন, আমি ব্যক্তিগতভাবে দেখতে পাই যে আমার সাথে সম্পত্তির পরিবর্তনের মতো জিনিসের জন্য অনেকগুলি ইভেন্ট তৈরির প্রবণতা রয়েছে (বিশেষত যখন একে অপরের সাথে যোগাযোগ করে এমন ভিউ মডেলগুলি দিয়ে এমভিভিএম করার সময়) বা যেখানে ইভেন্টটি রয়েছে একটি একক প্যারামিটার বেশিরভাগ সময় এই ইভেন্টগুলি রূপ ধারণ করে public event Action<[classtype], bool> [PropertyName]Changed;বা করে public event Action SomethingHappened;। এই ক্ষেত্রে, দুটি সুবিধা আছে। প্রথমত, আমি ইস্যুকারী ক্লাসের জন্য একটি টাইপ পাই। যদি MyClassইভেন্টটি ঘোষণা করে এবং একমাত্র ক্লাস হয় তবে আমি MyClassইভেন্ট হ্যান্ডলারের সাথে কাজ করার একটি স্পষ্ট উদাহরণ পাই । দ্বিতীয়ত, সম্পত্তি পরিবর্তনের ইভেন্টের মতো সাধারণ ইভেন্টগুলির জন্য পরামিতিগুলির অর্থ সুস্পষ্ট এবং ইভেন্ট হ্যান্ডলারের নামে বিবৃত এবং আমাকে এই ধরণের ইভেন্টের জন্য অগণিত শ্রেণি তৈরি করতে হবে না।


অসাধারণ ব্লগ পোস্ট। আপনি এই থ্রেডটি পড়লে অবশ্যই একটি পঠনযোগ্য!
ভেক্সির 18

1
বিশদ এবং সুচিন্তিত উত্তর যা উপসংহারের পিছনে যুক্তি ব্যাখ্যা করে
মাইকেটি

18

বেশিরভাগ অংশে, আমি বলতে চাই যে নকশাটি অনুসরণ করুন। আমি করেছি নির্দিষ্ট কারণের জন্য তা থেকে বিচ্যুত, কিন্তু খুব কমই, এবং। ঘটনাচক্রে, আমার কাছে সবচেয়ে বড় সমস্যাটি হ'ল আমি সম্ভবত একটি ব্যবহার করব Action<SomeObjectType>, পরে আমাকে অতিরিক্ত সম্পত্তি যুক্ত করতে এবং মাঝে মাঝে দ্বি-উপায় সম্পত্তি ব্যবহার করতে (ভাবুন Handled, বা অন্যান্য প্রতিক্রিয়া-ইভেন্ট যেখানে গ্রাহককে ইভেন্ট অবজেক্টে একটি সম্পত্তি সেট করতে হবে )। এবং একবার আপনি এই লাইনটি শুরু করার পরে, আপনি পাশাপাশি কিছুটির EventHandler<T>জন্য ব্যবহার করতে পারেন T


14

যখন আপনার কোডটি 300,000 লাইনের প্রকল্পের মধ্যে থাকে তখন একটি শব্দযুক্ত পদ্ধতির সুবিধা আসে comes

অ্যাকশনটি ব্যবহার করে, যেমন আপনার আছে, আমাকে বল, ইনট এবং ব্লা কী তা বলার উপায় নেই। যদি আপনার ক্রিয়াকলাপটি এমন কোনও বিষয়কে পাস করে যা পরামিতিগুলি সংজ্ঞায়িত করে তবে ঠিক আছে ok

কোনও ইভেন্টহ্যান্ডলার ব্যবহার করে যা ইভেন্টআরগস চেয়েছিল এবং যদি আপনি যদি তাদের ডায়াগনস্টিক্স এজসের বৈশিষ্ট্যগুলির জন্য গেটসদের সাথে তাদের উদ্দেশ্য সম্পর্কে মন্তব্য করেছিলেন তবে আপনি আবেদনটি আরও বোধগম্য হবে। এছাড়াও, দয়া করে ডায়াগনস্টিক্সআর্গস কনস্ট্রাক্টরে যুক্তি বা সম্পূর্ণ যুক্তির নাম দিন।


6

যদি আপনি স্ট্যান্ডার্ড ইভেন্টের প্যাটার্নটি অনুসরণ করেন, তবে ইভেন্টের ফায়ারিংয়ের চেকিং নিরাপদ / সহজ করতে আপনি একটি এক্সটেনশন পদ্ধতি যুক্ত করতে পারেন। (যেমন নীচের কোডটি সেফফায়ার () নামক একটি এক্সটেনশন পদ্ধতি যুক্ত করে যা নাল চেক করে, পাশাপাশি (স্পষ্টতই) ঘটনাটিকে প্রভাবিত করতে পারে এমন নাল রেস-কন্ডিশন থেকে নিরাপদ থাকতে ইভেন্টটিকে একটি পৃথক ভেরিয়েবলে অনুলিপি করে))

(যদিও নাল বস্তুগুলিতে আপনার সম্প্রসারণের পদ্ধতিগুলি ব্যবহার করা উচিত কিনা তা আমি দুটি ধরণের মনে করি ...)

public static class EventFirer
{
    public static void SafeFire<TEventArgs>(this EventHandler<TEventArgs> theEvent, object obj, TEventArgs theEventArgs)
        where TEventArgs : EventArgs
    {
        if (theEvent != null)
            theEvent(obj, theEventArgs);
    }
}

class MyEventArgs : EventArgs
{
    // Blah, blah, blah...
}

class UseSafeEventFirer
{
    event EventHandler<MyEventArgs> MyEvent;

    void DemoSafeFire()
    {
        MyEvent.SafeFire(this, new MyEventArgs());
    }

    static void Main(string[] args)
    {
        var x = new UseSafeEventFirer();

        Console.WriteLine("Null:");
        x.DemoSafeFire();

        Console.WriteLine();

        x.MyEvent += delegate { Console.WriteLine("Hello, World!"); };
        Console.WriteLine("Not null:");
        x.DemoSafeFire();
    }
}

4
... আপনি কি অ্যাকশন <টি> দিয়ে একই কাজ করতে পারবেন না? SafeFire <T> (এই ক্রিয়া <T> দ্য ইভেন্ট, টি দ্য এজেন্টস) এর জন্য কাজ করা উচিত ... এবং "কোথায়" ব্যবহার করার দরকার নেই
বিচওয়াক্কার

6

আমি বুঝতে পারি যে এই প্রশ্নটি 10 ​​বছরেরও বেশি পুরানো, তবে এটি আমার কাছে উপস্থিত হয়েছে যে কেবল সর্বাধিক সুস্পষ্ট উত্তরই সম্বোধন করা হয়নি, তবে এটি সম্ভবত প্রশ্নটি থেকে পরিষ্কার নয় যে প্রচ্ছদের অধীনে কী চলছে তার একটি ভাল বোঝাপড়া। এছাড়াও, দেরীতে বাইন্ডিং এবং ডেলিগেটস এবং ল্যাম্বডাসের ক্ষেত্রে এর অর্থ কী তা সম্পর্কে আরও প্রশ্ন রয়েছে (পরে আরও) more

প্রথমে ঘরে 800 পাউন্ডের হাতি / গরিলা সম্বোধন করুন, কখন eventবনাম Action<T>/ Func<T>:

  • একটি বিবৃতি বা পদ্ধতি কার্যকর করতে একটি ল্যাম্বডা ব্যবহার করুন। ব্যবহার করুন eventযখন আপনি একাধিক বিবৃতি / lambdas / ফাংশন সঙ্গে একটি প্রকা / সদ মডেল যে চালানো হবে আরো চাই (এটি হল প্রধান এটি ব্যাটের ডানদিকে পার্থক্য) ।
  • আপনি যখন অভিব্যক্তি গাছগুলিতে বিবৃতি / ফাংশনগুলি সংকলন করতে চান তখন ল্যাম্বডা ব্যবহার করুন। আপনি যখন আরও বেশি traditionalতিহ্যবাহী দেরী বাইন্ডিং যেমন প্রতিচ্ছবি এবং সিওএম আন্তঃবিদ্যায় ব্যবহৃত হিসাবে অংশ নিতে চান তখন প্রতিনিধি / ইভেন্টগুলি ব্যবহার করুন।

কোনও ইভেন্টের উদাহরণ হিসাবে, একটি ছোট কনসোল অ্যাপ্লিকেশন ব্যবহার করে ইভেন্টগুলির একটি সহজ এবং 'স্ট্যান্ডার্ড' সেটটিকে তারের আপ করতে দিন:

public delegate void FireEvent(int num);

public delegate void FireNiceEvent(object sender, SomeStandardArgs args);

public class SomeStandardArgs : EventArgs
{
    public SomeStandardArgs(string id)
    {
        ID = id;
    }

    public string ID { get; set; }
}

class Program
{
    public static event FireEvent OnFireEvent;

    public static event FireNiceEvent OnFireNiceEvent;


    static void Main(string[] args)
    {
        OnFireEvent += SomeSimpleEvent1;
        OnFireEvent += SomeSimpleEvent2;

        OnFireNiceEvent += SomeStandardEvent1;
        OnFireNiceEvent += SomeStandardEvent2;


        Console.WriteLine("Firing events.....");
        OnFireEvent?.Invoke(3);
        OnFireNiceEvent?.Invoke(null, new SomeStandardArgs("Fred"));

        //Console.WriteLine($"{HeightSensorTypes.Keyence_IL030}:{(int)HeightSensorTypes.Keyence_IL030}");
        Console.ReadLine();
    }

    private static void SomeSimpleEvent1(int num)
    {
        Console.WriteLine($"{nameof(SomeSimpleEvent1)}:{num}");
    }
    private static void SomeSimpleEvent2(int num)
    {
        Console.WriteLine($"{nameof(SomeSimpleEvent2)}:{num}");
    }

    private static void SomeStandardEvent1(object sender, SomeStandardArgs args)
    {

        Console.WriteLine($"{nameof(SomeStandardEvent1)}:{args.ID}");
    }
    private static void SomeStandardEvent2(object sender, SomeStandardArgs args)
    {
        Console.WriteLine($"{nameof(SomeStandardEvent2)}:{args.ID}");
    }
}

আউটপুট নীচের মত দেখতে হবে:

এখানে চিত্র বর্ণনা লিখুন

Action<int>বা এর সাথে যদি আপনি একই করেন তবে Action<object, SomeStandardArgs>আপনি কেবল দেখতে পাবেন SomeSimpleEvent2এবংSomeStandardEvent2

ভিতরে কি চলছে event ?

যদি আমরা প্রসারিত করি FireNiceEvent, সংকলকটি আসলে নিম্নলিখিতটি তৈরি করছে (থ্রেড সিঙ্ক্রোনাইজেশনের ক্ষেত্রে আমি কিছু বিশদ বাদ দিয়েছি যা এই আলোচনার সাথে প্রাসঙ্গিক নয়):

   private EventHandler<SomeStandardArgs> _OnFireNiceEvent;

    public void add_OnFireNiceEvent(EventHandler<SomeStandardArgs> handler)
    {
        Delegate.Combine(_OnFireNiceEvent, handler);
    }

    public void remove_OnFireNiceEvent(EventHandler<SomeStandardArgs> handler)
    {
        Delegate.Remove(_OnFireNiceEvent, handler);
    }

    public event EventHandler<SomeStandardArgs> OnFireNiceEvent
    {
        add
        {
            add_OnFireNiceEvent(value)
        }
        remove
        {
            remove_OnFireNiceEvent(value)

        }
    }

সংকলকটি একটি প্রাইভেট ডেলিগেট ভেরিয়েবল উত্পন্ন করে যা শ্রেণীর নেমস্পেসের মধ্যে দৃশ্যমান নয় যেখানে এটি উত্পন্ন হয়। এই প্রতিনিধিটি হ'ল সাবস্ক্রিপশন পরিচালনা এবং দেরীতে বাধ্যতামূলক অংশগ্রহণের জন্য যা ব্যবহৃত হয় এবং জনসাধারণের মুখোমুখি ইন্টারফেসটি আমাদের পরিচিত +=এবং -=অপারেটররা সবাই জানতে পেরেছিলেন এবং ভালোবাসেন:)

এর স্কোপটি পরিবর্তন করে আপনি অ্যাড / রিমুভাল হ্যান্ডলারের কোডটি কাস্টমাইজ করতে পারেন FireNiceEvent সুরক্ষিত । এটি এখন বিকাশকারীদের লগিং বা সুরক্ষা হুকের মতো হুকগুলিতে কাস্টম হুক যুক্ত করতে দেয়। এটি সত্যিই এমন বেশ কয়েকটি শক্তিশালী বৈশিষ্ট্য তৈরি করে যা ব্যবহারকারীর ভূমিকা ইত্যাদির উপর ভিত্তি করে সাবস্ক্রিপশনটিতে কাস্টমাইজড অ্যাক্সেসযোগ্যতার অনুমতি দেয় আপনি ল্যাম্বডাস দিয়ে এটি করতে পারেন? (প্রকৃতপক্ষে আপনি কাস্টমাইজেশন এক্সপ্রেশন ট্রিগুলি দ্বারা করতে পারেন, তবে এটি এই প্রতিক্রিয়াটির পরিধি ছাড়িয়ে গেছে)।

এখানে কিছু প্রতিক্রিয়া থেকে কয়েকটি পয়েন্ট সম্বোধন করতে:

  • আরগস তালিকা Action<T>পরিবর্তন করে এবং প্রাপ্ত ক্লাসে বৈশিষ্ট্যগুলি পরিবর্তনের মধ্যে 'ভঙ্গুরতা' তেমন কোনও পার্থক্য নেই EventArgs। হয় কেবল একটি সংকলন পরিবর্তন প্রয়োজন হবে না, তারা উভয় একটি পাবলিক ইন্টারফেস পরিবর্তন হবে এবং সংস্করণ প্রয়োজন হবে। কোনও পার্থক্য নেই।

  • একটি শিল্পের মান যা সম্মানের সাথে এটি নির্ভর করে যে এটি কোথায় ব্যবহৃত হচ্ছে এবং কেন। Action<T>এবং এগুলি প্রায়শই আইওসি এবং ডিআইতে ব্যবহৃত হয় এবং eventপ্রায়শই জিইউআই এবং এমকিউ টাইপ ফ্রেমওয়ার্ক হিসাবে বার্তা রাউটিংয়ে ব্যবহৃত হয়। নোট করুন যে আমি প্রায়শই বলেছি , সবসময় না ।

  • প্রতিনিধিদের ল্যাম্বডাসের চেয়ে আলাদা জীবনকাল থাকে। একজনকে ক্যাপচার সম্পর্কেও সচেতন হতে হবে ... কেবল বন্ধের সাথে নয়, 'বিড়াল কী টানছিল তা দেখুন' এর ধারণার সাথেও। এটি মেমরির পদচিহ্ন / আজীবন পাশাপাশি পরিচালনা ওরফে ফাঁসকে প্রভাবিত করে।

আরও একটি জিনিস, আমি আগে উল্লেখ করেছি এমন কিছু জিনিস ... দেরীতে বাইন্ডিংয়ের ধারণা। লম্বা যখন 'লাইভ' হয়ে যায় তখন লিনকির মতো কাঠামো ব্যবহার করার সময় আপনি প্রায়শই এটি দেখতে পাবেন। এটি কোনও প্রতিনিধিকে দেরীতে আবদ্ধ করার চেয়ে খুব আলাদা, যা একাধিকবার ঘটতে পারে (যেমন ল্যাম্বডা সর্বদা উপস্থিত থাকে, তবে বাঁধাগুলি চাহিদা অনুযায়ী যতবার প্রয়োজন ততক্ষণে ঘটে), ল্যাম্বদার বিপরীতে, যা একবার হয়ে গেলে এটি হয়ে যায় done - যাদুটি চলে গেছে, এবং পদ্ধতি (গুলি) / সম্পত্তি (আইস) সর্বদা আবদ্ধ থাকবে। কিছু মনে রাখবেন।


4

এ খুঁজছি স্ট্যান্ডার্ড .NET ঘটনা নিদর্শন আমরা খুঁজে

। নেট ইভেন্টের প্রতিনিধিদের জন্য আদর্শ স্বাক্ষর হ'ল:

void OnEventRaised(object sender, EventArgs args);

[...]

যুক্তি তালিকায় দুটি যুক্তি রয়েছে: প্রেরক এবং ইভেন্টের যুক্তি। প্রেরকের সংকলনের টাইম টাইপটি হ'ল সিস্টেম.অজেক্ট, যদিও আপনি সম্ভবত আরও একটি উদ্ভূত প্রকারটি জানেন যা সর্বদা সঠিক would কনভেনশন দ্বারা, অবজেক্ট ব্যবহার করুন ।

একই পৃষ্ঠায় নীচে আমরা আদর্শ ইভেন্ট সংজ্ঞাটির একটি উদাহরণ পাই যা এটির মতো

public event EventHandler<EventArgs> EventName;

আমরা সংজ্ঞা ছিল

class MyClass
{
  public event Action<MyClass, EventArgs> EventName;
}

হ্যান্ডলার হতে পারে

void OnEventRaised(MyClass sender, EventArgs args);

যেখানে senderসঠিক ( আরও উত্পন্ন ) প্রকার রয়েছে।


দুঃখিত মন্তব্য করেছেন না যে পার্থক্য, হ্যান্ডলার স্বাক্ষর হয় যা এর উপকার হবে আরো সঠিকভাবে টাইপ করা sender
ব্যবহারকারী 1832484
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.