ফর-লুপে ভেরিয়েবল ঘোষিত হয় স্থানীয় ভেরিয়েবল?


133

আমি দীর্ঘদিন ধরে সি # ব্যবহার করে আসছি তবে নিম্নলিখিতগুলি কখনই বুঝতে পারি নি:

 public static void Main()
 {
     for (int i = 0; i < 5; i++)
     {

     }

     int i = 4;  //cannot declare as 'i' is declared in child scope                
     int A = i;  //cannot assign as 'i' does not exist in this context
 }

সুতরাং যদি আমি এই নামের সাথে একটি ভেরিয়েবল ঘোষণা করতে না দিই তবে আমি কেন ব্লকের জন্য 'i' এর মানটি ব্যবহার করতে পারি না?

আমি ভেবেছিলাম যে ফোর-লুপ দ্বারা ব্যবহৃত পুনরাবৃত্তীয় ভেরিয়েবলটি কেবল তার পরিধিতেই বৈধ।


8
কারণ বাইরের ব্লক
স্কোপটিতে

3
আমি এটির একটি উপায় মনে করি (এবং কিছু কোড শৈলীর গাইডদের এটির প্রয়োজন হয়, বিশেষত গতিশীল-টাইপযুক্ত ভাষার জন্য) একটি স্কোপ হিসাবে ঘোষিত সমস্ত ভেরিয়েবলগুলি সেই সুযোগের শুরুতে ঘোষিত হতে পারে, যার অর্থ আপনার ফাংশনটি আবার লেখা যেতে পারেint i, A; for(int i = 0; i < 5; i++){ } i=4; A=i
কিথ

2
@ ভি 4 ভেন্ডেটা: এটি আরও অন্যান্য উপায়ে। অভ্যন্তরীণ ব্লক প্যারেন্ট ব্লকের একটি কালো বক্স।
সেবাস্তিয়ান মাচ

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

আমি এটিকে আদৌ উপলব্ধি করতে পারি নি তবে এটি পুরোপুরি খাঁটি বাধা বলে মনে হচ্ছে।
alan2here

উত্তর:


119

বাহ্য-স্কুপের ভেরিয়েবলগুলি অভ্যন্তরীণ স্কোপে বৈধ হওয়ায় আপনি যে কারণে বহিরাগত-স্কোপে ভেরিয়েবল উভয় ক্ষেত্রেই লুপের পাশাপাশি এবং লুপের বাইরে উভয় ক্ষেত্রে একই নামের সাথে একটি ভেরিয়েবল সংজ্ঞায়িত না করার কারণ। এর অর্থ হ'ল যদি এটির অনুমতি দেওয়া হয় তবে লুপের মধ্যে দুটি 'আই' ভেরিয়েবল থাকবে।

দেখুন: এমএসডিএন স্কোপস

বিশেষ করে:

স্থানীয় ভেরিয়েবল-ঘোষণার (বিভাগ 8.5.1) এ ঘোষণা করা একটি স্থানীয় ভেরিয়েবলের সুযোগ হ'ল সেই ব্লকটি যেখানে ঘোষণাপত্রটি ঘটে।

এবং

একটি বিবৃতি (বিভাগ 8.8.3) এর একটি জন্য প্রাথমিক জন্য ঘোষিত স্থানীয় ভেরিয়েবলের সুযোগ হ'ল-ইনিশিয়ালাইজার, শর্তাধীন, ফর-পুনরাবৃত্তকারী এবং বিবৃতিটির জন্য থাকা বিবৃতি।

এবং এছাড়াও: স্থানীয় পরিবর্তনশীল ঘোষণা (সি # নির্দিষ্টকরণের বিভাগ 8.5.1)

বিশেষ করে:

স্থানীয় ভেরিয়েবল-ঘোষণায় ঘোষিত স্থানীয় ভেরিয়েবলের সুযোগ হ'ল সেই ব্লকটি যেখানে ঘোষণাপত্রটি ঘটে।স্থানীয় ভেরিয়েবলের স্থানীয়-ভেরিয়েবল-ডিক্লেটারের পূর্বে যে পাঠ্য অবস্থানটিতে স্থানীয় ভেরিয়েবল উল্লেখ করা এটি ত্রুটি। স্থানীয় ভেরিয়েবলের ক্ষেত্রের মধ্যে, একই নামের সাথে অন্য একটি স্থানীয় ভেরিয়েবল বা ধ্রুবক ঘোষণা করা একটি সংকলন-সময় ত্রুটি।

(জোর আমার।)

যার অর্থ আপনার লুপটির iঅভ্যন্তরের স্কোপটি হ'ল ফর লুপ। যদিও iআপনার ফর-লুপের বাইরের ক্ষেত্রটি পুরো প্রধান পদ্ধতি প্লাস ফর লুপ। মানে আপনার iলুপের ভিতরে দুটি ঘটনা রয়েছে যা উপরেরটি অনুসারে অবৈধ।

আপনাকে কেন অনুমতি দেওয়া হচ্ছে না int A = i;তার কারণ int iহ'ল forলুপের মধ্যে কেবল ব্যবহারের জন্য স্কোপ করা আছে । সুতরাং এটি আর এর বাইরে প্রবেশযোগ্য নয়for লুপের ।

আপনি দেখতে পাচ্ছেন যে এই দুটি সমস্যাই স্কোপিংয়ের ফলাফল; প্রথম ইস্যু ( int i = 4;) এর ফলে লুপ স্কোপের মধ্যে দুটি iভেরিয়েবল হবে for। যদিও int A = i;সুযোগের বাইরে থাকা একটি চলকটিতে অ্যাক্সেসের ফলস্বরূপ।

পরিবর্তে আপনি যা করতে পারেন তা iপুরো পদ্ধতিতে স্কোপ হওয়ার ঘোষণা দেওয়া হয়েছে এবং তারপরে এটি দুটি পদ্ধতিতে এবং লুপ স্কোপে ব্যবহার করুন। এটি উভয় নিয়ম ভঙ্গ এড়াতে পারবেন।

public static void Main()
{
    int i;

    for (i = 0; i < 5; i++)
    {

    }

    // 'i' is only declared in the method scope now, 
    // no longer in the child scope -> valid.
    i = 4;

    // 'i' is declared in the method's scope -> valid. 
    int A = i;
}

সম্পাদনা :

এই কোডটি বেশ কার্যকরভাবে সংকলনের অনুমতি দেওয়ার জন্য সি # সংকলক অবশ্যই পরিবর্তন করা যেতে পারে। সর্বোপরি এই বৈধ:

for (int i = 0; i < 5; i++)
{
    Console.WriteLine(i);
}

for (int i = 5; i > 0; i--)
{
    Console.WriteLine(i);
}

তবে কী কোড লিখতে সক্ষম হবেন তা আপনার কোড পঠনযোগ্যতা এবং রক্ষণাবেক্ষণের পক্ষে কি সত্যই উপকারী হবে:

public static void Main()
{
    int i = 4;

    for (int i = 0; i < 5; i++)
    {
        Console.WriteLine(i);
    }

    for (int i = 5; i > 0; i--)
    {
        Console.WriteLine(i);
    }

    Console.WriteLine(i);
}

এখানে ভুলের সম্ভাবনা সম্পর্কে চিন্তা করুন, i0 বা 4 টি কি শেষ প্রিন্ট আউট করে? এখন এটি একটি খুব ছোট উদাহরণ, এটি অনুসরণ করা এবং ট্র্যাক করা বেশ সহজ তবে এটি iকোনও পৃথক নামে বাইরের ঘোষণার চেয়ে অবশ্যই অনেক কম রক্ষণাবেক্ষণযোগ্য এবং পঠনযোগ্য ।

বিশেষ দ্রষ্টব্য:

দয়া করে মনে রাখবেন, সি # এর স্কোপিং নিয়মগুলি সি ++ এর স্কোপিং বিধি থেকে পৃথক । সি ++ এ ভেরিয়েবলগুলি কেবলমাত্র স্কোপে যেখানে সেগুলি ব্লকের শেষ অবধি ঘোষণা করা হয়। যা আপনার কোডকে সি ++ এ একটি বৈধ নির্মাণ করবে।


উপলব্ধি করে, আমি মনে করি iযদিও এটি অভ্যন্তরীণ ভেরিয়েবলের ত্রুটি হওয়া উচিত ; এটা আমার কাছে আরও স্পষ্ট বলে মনে হচ্ছে
জর্জ ডেকেট

কিন্তু সুযোগটি কমান্ডের জন্য এবং তার {}? বা এর অর্থ তার পিতা-মাতা}}?
জন ভি

2
ঠিক আছে যদি আমি বিবৃতিটির পরে 'এ' ঘোষণা করি তবে এটি পরে লুপ হিসাবে ঘোষিত হিসাবে এটি বৈধ নয়। এজন্য একই নাম কেন ব্যবহার করা যায় না তা আমি পাই না।
জন ভি

9
সম্ভবত এই উত্তরটি সম্পূর্ণতার জন্য চিহ্নিত করা উচিত যে সি # স্কোপ নিয়মগুলি এই ক্ষেত্রে সি ++ এর চেয়ে আলাদা । সি ++ তে, ভেরিয়েবলগুলি কেবলমাত্র সেই সুযোগ থেকে থাকে যেখানে সেগুলি ব্লকের শেষ অবধি ঘোষিত হয় (দেখুন msdn.microsoft.com/en-us/library/b7kfh662(v=vs.80).aspx )।
এ্যাট

2
নোট করুন যে জাভা সি ++ এবং সি # এর মধ্যে একটি মধ্যবর্তী পদ্ধতির গ্রহণ করে: এটি ওপির উদাহরণ হিসাবে জাভাতে বৈধ হবে, তবে যদি বাহ্যিক iসংজ্ঞাটি লুপের আগে স্থানান্তরিত হয় তবে অভ্যন্তরীণ iসংজ্ঞাটি অবৈধ হিসাবে চিহ্নিত হবে।
নিকোলা মুসাত্তি

29

J.Kommer এর উত্তরটি সঠিক: সংক্ষেপে, এটা বেআইনি জন্য স্থানীয় পরিবর্তনশীল একটি ঘোষণা করা স্থানীয় পরিবর্তনশীল ঘোষণা স্থান যে ওভারল্যাপ অন্য স্থানীয় পরিবর্তনশীল ঘোষণা স্থান একই নামের একটি স্থানীয় রয়েছে।

সি # এর অতিরিক্ত নিয়ম রয়েছে যা এখানেও লঙ্ঘন করা হয়েছে। অতিরিক্ত নিয়মটি হল যে কোনও সাধারণ নামটি দুটি ভিন্ন ওভারল্যাপিং স্থানীয় ভেরিয়েবল ঘোষণার জায়গাগুলির ভিতরে দুটি পৃথক সত্তা উল্লেখ করার জন্য ব্যবহার করা অবৈধ। সুতরাং কেবল আপনার উদাহরণটি অবৈধ নয়, এটিও অবৈধ:

class C
{
    int x;
    void M()
    {
        int y = x;
        if(whatever)
        {
            int x = 123;

কারণ এখন "y" এর স্থানীয় ভেরিয়েবল ডিক্লেয়ারেশন স্পেসের ভিতরে "x" নামটি দুটি পৃথক জিনিস বোঝাতে ব্যবহৃত হয়েছে - "this.x" এবং স্থানীয় "x"।

এই সমস্যাগুলির আরও বিশ্লেষণের জন্য http://blogs.msdn.com/b/ericlippert/archive/tags/simple+names/ দেখুন ।


2
এছাড়াও, এটি আকর্ষণীয়ভাবে মনে রাখবেন যে আপনি যখন পরিবর্তন করবেন তখন আপনার উদাহরণ কোডটি সংকলন করবেint y = this.x;
ফিল

4
@ ফিল: সঠিক। this.xএকটি সাধারণ নাম নয়
এরিক লিপার্ট

13

iলুপের পরে পদ্ধতির ভিতরে ডিক্লেয়ার এবং ব্যবহার করার একটি উপায় রয়েছে :

static void Main()
{
    for (int i = 0; i < 5; i++)
    {

    }

    {
        int i = 4;
        int A = i;
    }
}

আপনি জাভাতে এটি করতে পারেন (এটি সি থেকে নিশ্চিত হতে পারে যে আমি নিশ্চিত নই)। পরিবর্তনশীল নামের জন্য এটি অবশ্যই কিছুটা অগোছালো।


হ্যাঁ এটি সি / সি ++ থেকে উদ্ভূত।
ব্র্যাঙ্কো দিমিত্রিজেভিক

1
আমি এই আগে জানতাম না। ঝরঝরে ভাষার বৈশিষ্ট্য!

@ ম্যাথিয়াসলাইক্কেগার্ড লরেনজেন হ্যাঁ
ক্রিস এস

7

আপনি ঘোষণা হত i সামনে আপনার forলুপ, আপনি মনে এটি এখনও লুপ ভিতরে এটা ডিক্লেয়ার বৈধ হতে উচিত?

না, কারণ তখন দুজনের স্কোপ ওভারল্যাপ হবে।

না করতে সক্ষম হিসাবে int A=i;, ভাল এটি কেবল কারণ লুপ iবিদ্যমান কারণ forএটি করা উচিত।


7

জে.কমার এর উত্তর ছাড়াও (+1 বিটিডাব্লু)। নেট স্কোপের জন্য এটি স্ট্যান্ডার্ডে রয়েছে:

ব্লক যদি আপনি কোনও ব্লক কনস্ট্রাক্টের মধ্যে যেমন একটি আইএফ স্টেটমেন্টের মধ্যে ভেরিয়েবল ঘোষণা করেন তবে সেই ভেরিয়েবলের স্কোপটি কেবলমাত্র ব্লকের সমাপ্তি অবধি থাকে। প্রক্রিয়া শেষ না হওয়া পর্যন্ত জীবনকাল।

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

সুতরাং int- এ আমি লুপ জন্য হেডার মধ্যে decalared শুধুমাত্র লুপ ব্লক জন্য সময় সুযোগ হবে, কিন্তু এটা সারা জীবনের পর্যন্ত স্থায়ী হয় Main()কোড সমাপ্ত হবে।


5

এটি সম্পর্কে চিন্তা করার সবচেয়ে সহজ উপায় হ'ল I এর বাহ্যিক ঘোষণাকে লুপের উপরে নিয়ে যাওয়া। এটি তখন সুস্পষ্ট হওয়া উচিত।

এটি উভয় উপায়ে একই সুযোগ, সুতরাং এটি করা যায় না।


4

এছাড়াও সি # এর নিয়মগুলি কঠোরভাবে প্রোগ্রাম করার ক্ষেত্রে অনেক সময় প্রয়োজন হয় না, তবে আপনার কোডটি পরিষ্কার এবং পঠনযোগ্য রাখার জন্য রয়েছে।

উদাহরণস্বরূপ, তারা এটি তৈরি করতে পারত যাতে আপনি এটি লুপের পরে সংজ্ঞায়িত করেন তবে এটি ঠিক আছে, তবে আপনার কোডটি পড়ে এবং সংজ্ঞা রেখাটি মিস করেছেন এমন কেউ ভাবতে পারে এটি লুপের ভেরিয়েবলের সাথে করতে পারে।


2

কোমারের উত্তরটি প্রযুক্তিগতভাবে সঠিক। আমাকে এটি একটি স্বতন্ত্র অন্ধ-পর্দার রূপক দিয়ে প্যারাফ্রেজ করতে দিন।

ফর-ব্লক এবং ঘেরযুক্ত বাইরের ব্লকের মধ্যে একটি উপায় অন্ধ পর্দা রয়েছে যেমন ফোর-ব্লকের মধ্যে থাকা কোডটি বাইরের কোড দেখতে পারে তবে বাইরের ব্লকের কোডটি ভিতরে কোড দেখতে পায় না।

যেহেতু বাইরের কোডটি ভিতরে দেখতে পারে না তাই এটি ভিতরে ঘোষিত কিছু ব্যবহার করতে পারে না। তবে যেহেতু ফোর-ব্লকের কোডটি ভিতরে এবং বাইরে উভয়ই দেখতে পাচ্ছে, তাই উভয় স্থানে ঘোষিত একটি পরিবর্তনশীল নামটি দ্ব্যর্থহীনভাবে ব্যবহার করা যাবে না।

সুতরাং হয় আপনি এটি দেখতে পাচ্ছেন না, বা আপনি সি #!


0

এটিকে একইভাবে দেখুন যেন আপনি কোনও ব্লকে একটি ঘোষণা করতে পারেন :intusing

using (int i = 0) {
  // i is in scope here
}
// here, i is out of scope

তবে যেহেতু intবাস্তবায়ন হয় না IDisposable, তাই এটি করা যায় না। এটি কোনও ব্যক্তিকে কীভাবে intব্যক্তিগত স্কোপে রাখা হয় তা কল্পনা করতে সহায়তা করতে পারে ।

আর একটি উপায় বলতে হবে,

if (true) {
  int i = 0;
  // i is in scope here
}
// here, i is out of scope

আশা করি এটি যা চলছে তা কল্পনা করতে সহায়তা করে।

আমি এই বৈশিষ্ট্যটি সত্যই পছন্দ করি, কারণ লুপের intভিতর থেকে ডিক্লেয়ার করা forকোডটি সুন্দর এবং আঁটকে রাখে।


ডব্লিউটিএফ? আপনি যদি কোনও এনইজি ট্যাগ করতে চলেছেন, তবে বলটি বলুন।
jp2code

ডাউনভোটার নয় এবং আমি মনে করি এর সাথে তুলনা usingকরা বেশ ঠিক আছে, যদিও শব্দার্থবিজ্ঞানের তুলনায় এটি আলাদা আলাদা (সম্ভবত এটি কেন হ্রাস পেয়েছিল)। নোট যে if (true)অপ্রয়োজনীয়। এটি সরান এবং আপনার একটি স্কোপিং ব্লক রয়েছে।
আবেল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.