সি # তে ইভেন্ট হ্যান্ডলারগুলি স্পষ্টভাবে অপসারণ করা কি প্রয়োজনীয়?


120

আমার একটি ক্লাস রয়েছে যা কয়েকটি ইভেন্ট উপস্থাপন করে। এই শ্রেণিটি বিশ্বব্যাপী ঘোষিত হয় তবে বিশ্বব্যাপী ঘোষণার উপর ভিত্তি করে নয় - এটি প্রয়োজনীয় পদ্ধতিগুলির মধ্যে প্রয়োজনীয় ভিত্তিতে উদাহরণস্বরূপ প্রকাশিত হয়েছে।

ক্লাসটি যখন কোনও পদ্ধতিতে প্রয়োজন হয় ততবারই এটি উদাহরণস্বরূপ হয় এবং ইভেন্ট হ্যান্ডলারগুলি নিবন্ধিত হয়। পদ্ধতিটি সুযোগের বাইরে যাওয়ার আগে কি ইভেন্ট হ্যান্ডলারগুলি স্পষ্টভাবে অপসারণ করা দরকার?

পদ্ধতিটি সুযোগের বাইরে চলে গেলে ক্লাসের উদাহরণটি যায়। সুযোগের বাইরে চলে যাওয়া ইভেন্টের সাথে নিবন্ধিত ইভেন্ট হ্যান্ডলারের কী মেমরির পদচিহ্ন অন্তর্ভুক্ত রয়েছে? (আমি ভাবছি যে ইভেন্ট হ্যান্ডলারটি জিসিটিকে ক্লাসের উদাহরণটি আর উল্লেখ করা হচ্ছে না বলে ধরে রাখে))

উত্তর:


184

আপনার ক্ষেত্রে, সবকিছু ঠিক আছে। এটি অবজেক্ট যা ইভেন্টগুলি প্রকাশ করে যা ইভেন্ট হ্যান্ডলারের লক্ষ্যগুলিকে লাইভ রাখে । সুতরাং আমি যদি:

publisher.SomeEvent += target.DoSomething;

তারপরে publisherএকটি রেফারেন্স রয়েছে targetতবে অন্যভাবে নয়।

আপনার ক্ষেত্রে, প্রকাশক আবর্জনা সংগ্রহের জন্য যোগ্য হতে চলেছেন (ধরে নেওয়া যায় এর সাথে অন্য কোনও উল্লেখ নেই) সুতরাং এটি ইভেন্ট হ্যান্ডলার লক্ষ্যগুলির একটি রেফারেন্স পেয়েছে তা অপ্রাসঙ্গিক।

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

BandwidthUI ui = new BandwidthUI();
transferService.BandwidthChanged += ui.HandleBandwidthChange;
// Suppose this blocks until the transfer is complete
transferService.Transfer(source, destination);
// We now have to unsusbcribe from the event
transferService.BandwidthChanged -= ui.HandleBandwidthChange;

(আপনি ইভেন্ট হ্যান্ডলারটি ফাঁস করবেন না তা নিশ্চিত করার জন্য আপনি আসলে একটি শেষ অবধি ব্যবহার করতে চান we) ​​আমরা যদি সাবস্ক্রাইব না করি BandwidthUIতবে ট্রান্সফার পরিষেবাটি অন্তত দীর্ঘকাল বেঁচে থাকবে।

ব্যক্তিগতভাবে আমি খুব কমই এটিকে ঘুরে আসি - সাধারণত আমি যদি কোনও ইভেন্টের সাবস্ক্রাইব করি তবে সেই ইভেন্টের লক্ষ্যটি অন্ততপক্ষে প্রকাশক হিসাবে বেঁচে থাকে - উদাহরণস্বরূপ, একটি ফর্ম যতক্ষণ থাকবে তাতে যতক্ষণ বাটন থাকবে ততক্ষণ দীর্ঘস্থায়ী থাকবে। এই সম্ভাব্য সমস্যাটি সম্পর্কে জানার পক্ষে মূল্যবান, তবে আমি মনে করি কিছু লোকেরা যখন তাদের প্রয়োজন না হয় তখন এটি নিয়ে উদ্বিগ্ন হয়, কারণ তারা জানে না যে রেফারেন্সগুলি প্রায় কোন পথে যায়।

সম্পাদনা: এটি জোনাথন ডিকিনসনের মন্তব্যের জবাব দেওয়ার জন্য। প্রথমত, ডেলিগেট.একুয়ালস (অবজেক্ট) এর জন্য দস্তাবেজগুলি দেখুন যা স্পষ্টভাবে সাম্যের আচরণ দেয়।

দ্বিতীয়ত, আনসস্ক্রিপশন কাজ করার জন্য এখানে একটি ছোট কিন্তু সম্পূর্ণ প্রোগ্রামটি রয়েছে:

using System;

public class Publisher
{
    public event EventHandler Foo;

    public void RaiseFoo()
    {
        Console.WriteLine("Raising Foo");
        EventHandler handler = Foo;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
        else
        {
            Console.WriteLine("No handlers");
        }
    }
}

public class Subscriber
{
    public void FooHandler(object sender, EventArgs e)
    {
        Console.WriteLine("Subscriber.FooHandler()");
    }
}

public class Test
{
    static void Main()
    {
         Publisher publisher = new Publisher();
         Subscriber subscriber = new Subscriber();
         publisher.Foo += subscriber.FooHandler;
         publisher.RaiseFoo();
         publisher.Foo -= subscriber.FooHandler;
         publisher.RaiseFoo();
    }
}

ফলাফল:

Raising Foo
Subscriber.FooHandler()
Raising Foo
No handlers

(মনো এবং .NET 3.5SP1 এ পরীক্ষিত))

আরও সম্পাদনা:

এটি প্রমাণ করার জন্য যে কোনও ইভেন্ট প্রকাশক সংগ্রহ করা যেতে পারে যখন সেখানে কোনও গ্রাহকের উল্লেখ রয়েছে।

using System;

public class Publisher
{
    ~Publisher()
    {
        Console.WriteLine("~Publisher");
        Console.WriteLine("Foo==null ? {0}", Foo == null);
    }

    public event EventHandler Foo;
}

public class Subscriber
{
    ~Subscriber()
    {
        Console.WriteLine("~Subscriber");
    }

    public void FooHandler(object sender, EventArgs e) {}
}

public class Test
{
    static void Main()
    {
         Publisher publisher = new Publisher();
         Subscriber subscriber = new Subscriber();
         publisher.Foo += subscriber.FooHandler;

         Console.WriteLine("No more refs to publisher, "
             + "but subscriber is alive");
         GC.Collect();
         GC.WaitForPendingFinalizers();         

         Console.WriteLine("End of Main method. Subscriber is about to "
             + "become eligible for collection");
         GC.KeepAlive(subscriber);
    }
}

ফলাফল (.NET 3.5SP1 এ; মনো এখানে কিছুটা অদ্ভুত আচরণ করবে বলে মনে হচ্ছে that কিছু সময়ের মধ্যে এটি খতিয়ে দেখবে):

No more refs to publisher, but subscriber is alive
~Publisher
Foo==null ? False
End of Main method. Subscriber is about to become eligible for collection
~Subscriber

2
আমি এটির সাথে একমত আছি তবে সম্ভব হলে আপনি "তবে গ্রাহকরা হতে চান না" এর অর্থ যা বোঝাতে চেয়েছেন তার সংক্ষিপ্ত বিবরণ বা অগ্রাধিকার দিতে পারেন?
পিটার ম্যাকজি

@ জোন: অনেক প্রশংসা করা হয়েছে, এটি সাধারণ নয় তবে আপনি যেমন বলেছিলেন আমি অযথা মানুষকে এ নিয়ে উদ্বিগ্ন হতে দেখেছি।
পিটার ম্যাকজি

- = কাজ করে না। - = একটি নতুন প্রতিনিধি ফলাফল করবে, এবং প্রতিনিধিরা লক্ষ্য পদ্ধতি ব্যবহার করে সমতা পরীক্ষা করে না, তারা একটি বস্তু করে। নতুন প্রতিনিধি তালিকায় উপস্থিত নেই: এর কোনও প্রভাব নেই (এবং অদ্ভুতভাবে কোনও ত্রুটি ফেলে না) doesn't
জোনাথন সি ডিকিনসন

2
@ জোনাথন: না, প্রতিনিধিরা লক্ষ্য পদ্ধতিটি ব্যবহার করে সমতা পরীক্ষা করে। একটি সম্পাদনায় প্রমাণ করা হবে।
জন স্কিটি

আমি স্বীকার করি আমি বেনামে প্রতিনিধিদের সাথে বিভ্রান্ত হয়ে পড়েছি।
জোনাথন সি ডিকিনসন

8

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

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

ইভেন্ট হ্যান্ডলারগুলির মাধ্যমে যদি ক্লাসটি এখনও নিবন্ধিত হয় তবে এটি এখনও পৌঁছনীয়। এটি এখনও একটি জীবন্ত অবজেক্ট। কোনও ইভেন্ট গ্রাফ অনুসরণ করে এমন একটি জিসি এটি সংযুক্ত দেখতে পাবে। হ্যাঁ, আপনি স্পষ্টভাবে ইভেন্ট হ্যান্ডলারগুলি সরাতে চাইবেন।

কেবলমাত্র বস্তুটির মূল বরাদ্দের সুযোগ ছাড়ার অর্থ এই নয় যে এটি জিসির প্রার্থী। যতক্ষণ একটি লাইভ রেফারেন্স থাকবে ততক্ষণ তা লাইভ।


1
আমি বিশ্বাস করি না যে এখানে কোনও আনসাবস্ক্রিপশন জরুরী - জিসি ইভেন্ট প্রকাশকের কাছ থেকে রেফারেন্সগুলি দেখে , এটি নয়, এবং এটিই এখানে প্রকাশক যার সম্পর্কে আমরা উদ্বিগ্ন।
জন স্কিটি

@ জোন স্কিকেট: আপনি ঠিক বলেছেন। আমি প্রশ্নটি পিছনে পড়েছি। আমি বাস্তবতা প্রতিফলিত করতে আমার উত্তর সংশোধন করেছি।
এডি 14
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.