সত্যিই কি ঘটে যায় চেষ্টা {রিটার্ন এক্স; } অবশেষে {x = নাল; } বিবৃতি?


259

আমি এই প্রশ্নটি অন্য প্রশ্নের মধ্যে দেখেছি এবং ভাবছিলাম যে কেউ যদি আমাকে ব্যাখ্যা করতে পারে যে পৃথিবীতে এটি কীভাবে কাজ করে?

try { return x; } finally { x = null; }

আমি বলতে চাইছি, বক্তব্যটি দেওয়ার পরেfinally কি ক্লজটি বাস্তবায়ন করে ? এই কোডটি থ্রেড-অনিরাপদ কীভাবে? আপনি কি এই অতিরিক্ত কোনও হ্যাকারি সম্পর্কে ভাবতে পারেন যা এই হ্যাকটি আর্ট করা যায় ?returntry-finally

উত্তর:


235

না - আইএল স্তরে আপনি কোনও ব্যতিক্রম-পরিচালনা করা ব্লকের ভিতরে ফিরে আসতে পারবেন না। এটি মূলত এটিকে একটি পরিবর্তনশীল হিসাবে সংরক্ষণ করে এবং পরে ফিরে আসে

যেমন:

int tmp;
try {
  tmp = ...
} finally {
  ...
}
return tmp;

উদাহরণস্বরূপ (প্রতিফলক ব্যবহার করে):

static int Test() {
    try {
        return SomeNumber();
    } finally {
        Foo();
    }
}

সংকলন:

.method private hidebysig static int32 Test() cil managed
{
    .maxstack 1
    .locals init (
        [0] int32 CS$1$0000)
    L_0000: call int32 Program::SomeNumber()
    L_0005: stloc.0 
    L_0006: leave.s L_000e
    L_0008: call void Program::Foo()
    L_000d: endfinally 
    L_000e: ldloc.0 
    L_000f: ret 
    .try L_0000 to L_0008 finally handler L_0008 to L_000e
}

এটি মূলত একটি স্থানীয় ভেরিয়েবল ( CS$1$0000) ঘোষণা করে , মানটিকে ভেরিয়েবলের মধ্যে রাখে (হ্যান্ডলড ব্লকের অভ্যন্তরে), তারপরে ব্লকটি বেরিয়ে আসার পরে ভেরিয়েবলটি লোড করে, তারপরে এটি প্রদান করে। প্রতিচ্ছবি এটিকে এটি রেন্ডার করে:

private static int Test()
{
    int CS$1$0000;
    try
    {
        CS$1$0000 = SomeNumber();
    }
    finally
    {
        Foo();
    }
    return CS$1$0000;
}

10
এই কি ঠিক না যা অক্সিডিয়ো বলেছিল: শেষ পর্যন্ত রিটার্নের মান গণনার পরে এবং সত্যই ফানকিজিয়ন থেকে ফিরে আসার আগে মৃত্যুদন্ড কার্যকর করা হয় ???
মিমি মিমি মিমি মম

"ব্যতিক্রম-পরিচালিত ব্লক" আমি মনে করি ব্যতিক্রম এবং ব্যতিক্রম হ্যান্ডলিংয়ের সাথে এই দৃশ্যের কোনও যোগসূত্র নেই। এটি কীভাবে .NET শেষ অবধি রিসোর্স গার্ড নির্মাণ কার্যকর করে imple
g.pickardou

361

পরিশেষে বিবৃতি কার্যকর করা হয়, কিন্তু ফেরতের মান প্রভাবিত হয় না। কার্যকর করার আদেশটি হ'ল:

  1. রিটার্ন স্টেটমেন্ট কার্যকর করার আগে কোড
  2. রিটার্ন বিবৃতিতে অভিব্যক্তি মূল্যায়ন করা হয়
  3. অবশেষে ব্লক কার্যকর করা হয়
  4. দ্বিতীয় ধাপে মূল্যায়ন করা ফলাফলগুলি ফিরে আসবে

এখানে প্রদর্শনের জন্য একটি ছোট প্রোগ্রাম:

using System;

class Test
{
    static string x;

    static void Main()
    {
        Console.WriteLine(Method());
        Console.WriteLine(x);
    }

    static string Method()
    {
        try
        {
            x = "try";
            return x;
        }
        finally
        {
            x = "finally";
        }
    }
}

এই প্রিন্টগুলি "চেষ্টা করুন" (কারণ এটি আবার ফিরে এসেছে) এবং তারপরে "শেষ পর্যন্ত" কারণ এটি এক্সের নতুন মান।

অবশ্যই, আমরা যদি কোনও মিউটেবল অবজেক্টের (যেমন একটি স্ট্রিংবিল্ডার) রেফারেন্স ফিরিয়ে দিই তবে অবশেষে ব্লকের অবজেক্টে যে কোনও পরিবর্তন করা হবে তা প্রত্যাবর্তনের সময় দৃশ্যমান হবে - এটি রিটার্ন মানকেই প্রভাবিত করে না (যা কেবলমাত্র একটি রেফারেন্স)।


আমি জিজ্ঞাসা করতে চাই, মৃত্যুদন্ড কার্যকর হওয়ার সময় লিখিত সি # কোডের জন্য উত্পন্ন ইন্টারমিডিয়েট ল্যাঙ্গুয়েজ (আইএল) দেখার জন্য ভিজ্যুয়াল স্টুডিওতে কোনও বিকল্প আছে কি না ....
এনিগমা রাজ্য

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

4
@ নিক: এটি বস্তুর পরিবর্তন নয় - এটি ভেরিয়েবলের পরিবর্তন । এটি ভেরিয়েবলের পূর্ববর্তী মানটি যে কোনও ক্ষেত্রে উল্লেখ করেছে সেটিকে প্রভাবিত করে না। সুতরাং না, এটি ব্যতিক্রম নয়।
জন স্কিটি

3
@ স্কিট তার মানে কি "রিটার্ন স্টেটমেন্টটি একটি অনুলিপি ফেরায়"?
প্রভাকরণ

4
@ প্রভাকরণ: ঠিক আছে এটি returnবিবৃতিটির পয়েন্টে অভিব্যক্তিটি মূল্যায়ন করে এবং সেই মানটি ফিরে আসবে। নিয়ন্ত্রণ পদ্ধতিটি ছেড়ে দেয় বলে অভিব্যক্তিটির মূল্যায়ন হয় না
জন স্কিটি

19

অবশেষে ধারাটি রিটার্নের স্টেটমেন্টের পরে কার্যকর হয় তবে কার্যত ফাংশন থেকে ফিরে আসার আগে। থ্রেড সুরক্ষার সাথে এর খুব কম সম্পর্ক রয়েছে বলে আমি মনে করি। এটি কোনও হ্যাক নয় - অবশেষে আপনি সর্বদা চালানোর গ্যারান্টিযুক্ত যা আপনার চেষ্টা ব্লক বা আপনার ক্যাচ ব্লকেই করুন না কেন।


13

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

"কী" ফিরে আসে তা সাধারণ প্রকারের মতো একই যুক্তি অনুসরণ করে:

class Test {
    public static Exception AnException() {
        Exception ex = new Exception("Me");
        try {
            return ex;
        } finally {
            // Reference unchanged, Local variable changed
            ex = new Exception("Not Me");
        }
    }
}

স্থানীয় ভেরিয়েবলটি শেষ অবধি একটি নতুন রেফারেন্স বরাদ্দ করার আগেই যে রেফারেন্সটি ফেরানো হচ্ছে তা ইতিমধ্যে মূল্যায়ন করা হয়েছে।

ফাঁসি কার্যকরভাবে:

class Test {
    public static Exception AnException() {
        Exception ex = new Exception("Me");
        Exception CS$1$0000 = null;
        try {
            CS$1$0000 = ex;
        } finally {
            // Reference unchanged, Local variable changed
            ex = new Exception("Not Me");
        }
        return CS$1$0000;
    }
}

পার্থক্যটি হ'ল এখনও অবজেক্টের বৈশিষ্ট্য / পদ্ধতি ব্যবহার করে পরিবর্তনীয় প্রকারের পরিবর্তন করা সম্ভব হবে যা আপনি সতর্ক না হলে অপ্রত্যাশিত আচরণের কারণ হতে পারে।

class Test2 {
    public static System.IO.MemoryStream BadStream(byte[] buffer) {
        System.IO.MemoryStream ms = new System.IO.MemoryStream(buffer);
        try {
            return ms;
        } finally {
            // Reference unchanged, Referenced Object changed
            ms.Dispose();
        }
    }
}

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

class ByRefTests {
    public static int One(out int i) {
        try {
            i = 1;
            return i;
        } finally {
            // Return value unchanged, Store new value referenced variable
            i = 1000;
        }
    }

    public static int Two(ref int i) {
        try {
            i = 2;
            return i;
        } finally {
            // Return value unchanged, Store new value referenced variable
            i = 2000;
        }
    }

    public static int Three(out int i) {
        try {
            return 3;
        } finally {
            // This is not a compile error!
            // Return value unchanged, Store new value referenced variable
            i = 3000;
        }
    }
}

অন্য কোন প্রবাহ কনস্ট্রাক্ট ভালো লেগেছে "ব্যবহার করে দেখুন রিটার্ন-পরিশেষে" তার স্থান নেই এবং গঠন এটা লেখার চেয়ে কোড খুঁজছি ক্লিনার জন্য অনুমতি দিতে পারেন আসলে করার প্রনয়ন। তবে গোটার হাত থেকে বাঁচতে অবশ্যই এটি অবশ্যই সাবধানে ব্যবহার করা উচিত।


4

যদি xস্থানীয় ভেরিয়েবল হয় তবে আমি বিন্দুটি দেখতে পাচ্ছি না, xপদ্ধতিটি বের হয়ে যাওয়ার পরে কার্যকরভাবে যেভাবে বাতিল হবে সেট করা হবে এবং প্রত্যাবর্তনের মানটির মূল্য বাতিল হবে না (যেহেতু এটি সেট করার জন্য কল করার আগে এটি রেজিস্টারে রাখা হয়েছিল) xto নাল)।

আমি কেবল তখনই এটি ঘটতে দেখি যদি আপনি ফেরতের সময় কোনও ক্ষেত্রের মান পরিবর্তনের গ্যারান্টি দিতে চান (এবং ফেরতের মান নির্ধারিত হওয়ার পরে)।


যদি স্থানীয় ভেরিয়েবলটি কোনও প্রতিনিধি দ্বারা ক্যাপচার না করা হয় :)
জন স্কিটি

তারপরে একটি বন্ধ রয়েছে এবং অবজেক্টটি আবর্জনা সংগ্রহ করা যাবে না, কারণ এখনও একটি রেফারেন্স রয়েছে।
পুনরাবৃত্তি

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