রেফ দ্বারা পাস তালিকা - আমাকে এই আচরণটি ব্যাখ্যা করতে সহায়তা করুন


109

নীচের প্রোগ্রামটি একবার দেখুন:

class Test
{
    List<int> myList = new List<int>();

    public void TestMethod()
    {
        myList.Add(100);
        myList.Add(50);
        myList.Add(10);

        ChangeList(myList);

        foreach (int i in myList)
        {
            Console.WriteLine(i);
        }
    }

    private void ChangeList(List<int> myList)
    {
        myList.Sort();

        List<int> myList2 = new List<int>();
        myList2.Add(3);
        myList2.Add(4);

        myList = myList2;
    }
}

আমি ধরে নিয়েছিলাম myListপাস হয়ে গেছে ref, এবং আউটপুট হবে

3
4

তালিকাটি প্রকৃতপক্ষে "রেফ দ্বারা পাস", তবে কেবল sortফাংশন কার্যকর হয়। নিম্নলিখিত বিবৃতিটির myList = myList2;কোনও প্রভাব নেই।

সুতরাং আউটপুট আসলে:

10
50
100

আপনি কি আমাকে এই আচরণটি ব্যাখ্যা করতে সহায়তা করতে পারেন? যদি প্রকৃতপক্ষে যথাযথভাবে পাসmyList না হয় (যেমন এটি myList = myList2কার্যকর না হওয়ার ফলে দেখা যায়), কীভাবে myList.Sort()কার্যকর হবে?

আমি এমনকি এই বিবৃতিটি কার্যকর না হওয়ার এবং আউটপুটটি ধরে নেওয়ার জন্য ধরে নিচ্ছিলাম:

100
50
10

কেবলমাত্র একটি পর্যবেক্ষণ (এবং আমি বুঝতে পারি যে সমস্যাটি এখানে সরল করা হয়েছে), তবে মনে হচ্ছে এটি আসলে নতুন তালিকা তৈরির পরিবর্তে ChangeListএকটি List<int>হওয়ার চেয়ে ফিরে আসা ভাল best void
জেফ বি

উত্তর:


110

আপনি একটি ক্ষণস্থায়ী হয় লিস্টে রেফারেন্স , কিন্তু আপনার নেই তালিকা পরিবর্তনশীল ক্ষণস্থায়ী রেফারেন্স দ্বারা - তাই আপনি কল যখন ভেরিয়েবলের মান এবং পরিবর্তন - (- "পয়েন্টার" মনে অর্থাত রেফারেন্স) অনুলিপি করা হয়েছে এর মান ভিতরে প্যারামিটারটি দেখা যায় নাChangeListChangeList TestMethod

চেষ্টা করে দেখুন:

private void ChangeList(ref List<int> myList) {...}
...
ChangeList(ref myList);

এরপরে এটি স্থানীয়-পরিবর্তনশীল myRef (যেমন ঘোষণা করা হয়েছে TestMethod) একটি রেফারেন্স দেয় ; এখন, আপনি যদি প্যারামিটার reassign ভিতরে ChangeListআপনার কাছে পরিবর্তনশীল পুনরায় নির্ধারণের হয় ভিতরে TestMethod


প্রকৃতপক্ষে আমি এটি করতে পারি, তবে আমি জানতে চাই যে বাছাই কীভাবে কার্যকর হচ্ছে
এনএমডিআর

6
@Ngm - যখন আপনি কল ChangeList, শুধুমাত্র রেফারেন্সের অনুলিপি করা হয়েছে - এটা একই বস্তুর হয়। আপনি যদি কোনওভাবে অবজেক্টটি পরিবর্তন করেন তবে সেই বস্তুর সাথে একটি উল্লেখ রয়েছে এমন সমস্ত কিছুই পরিবর্তনটি দেখতে পাবে।
মার্ক গ্র্যাভেল

225

প্রাথমিকভাবে, এটি গ্রাফিকভাবে নিম্নলিখিত হিসাবে উপস্থাপন করা যেতে পারে:

ইনিশ স্টেটস

তারপরে, বাছাই করা হয় myList.Sort(); সংগ্রহ বাছাই করুন

শেষ পর্যন্ত, যখন আপনি করেছেন:, myList' = myList2আপনি একটি উল্লেখটি হারিয়েছেন তবে আসলটি নয় এবং সংগ্রহটি বাছাই করা থাকে।

হারানো রেফারেন্স

আপনি যদি refতখন রেফারেন্স ( ) ব্যবহার করে থাকেন myList'এবং myListএকই (কেবলমাত্র একটি রেফারেন্স) হয়ে উঠবেন।

দ্রষ্টব্য: myList'আপনি যে প্যারামিটারটি ব্যবহার করেন তা উপস্থাপন করতে আমি ব্যবহার করি ChangeList(কারণ আপনি মূলটির মতো একই নাম দিয়েছেন)


20

এটি বোঝার একটি সহজ উপায় এখানে

  • আপনার তালিকাগুলি হ'ল একটি বস্তু created পরিবর্তনশীল myListহ'ল সেই বস্তুর একটি রেফারেন্স।

  • সি # তে আপনি কখনই বস্তুগুলি পাস করেন না, আপনি তাদের উল্লেখগুলি মান দ্বারা পাস করেন pass

  • যখন আপনি পাস করার রেফারেন্সের মাধ্যমে তালিকার অবজেক্টটিতে অ্যাক্সেস করেন ChangeList(উদাহরণস্বরূপ, বাছাই করার সময়) আসল তালিকাটি পরিবর্তন করা হয়।

  • ChangeListপদ্ধতিতে অ্যাসাইনমেন্টটি রেফারেন্সের মান হিসাবে তৈরি করা হয়, অতএব মূল তালিকায় কোনও পরিবর্তন করা হয় না (এখনও স্তূপে রয়েছে তবে পদ্ধতি ভেরিয়েবলের উপরে আর উল্লেখ করা হয়নি)।


10

এই লিঙ্কটি আপনাকে সি # তে রেফারেন্স দিয়ে পাস বুঝতে সহায়তা করবে। মূলত, যখন রেফারেন্স টাইপের কোনও অবজেক্টটি কোনও পদ্ধতির মান দ্বারা প্রেরণ করা হয়, কেবলমাত্র সেই পদ্ধতিগুলিতে যা অবজেক্টে পাওয়া যায় সেগুলি অবজেক্টের বিষয়বস্তুগুলিকে সংশোধন করতে পারে।

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

যদি আমরা রেফার কীওয়ার্ড ব্যবহার করে রেফারেন্স টাইপের অবজেক্টটি পাস করি তবে আমরা একই ভেরিয়েবলের জন্য অন্য কিছু বস্তুকে বরাদ্দ করতে পারি এবং এটি পুরো অবজেক্টকেই পরিবর্তন করে দেয়।

(সম্পাদনা করুন: এটি উপরে লিঙ্কিত ডকুমেন্টেশনের আপডেট সংস্করণ))


5

সি # একটি অগভীর অনুলিপি করে যখন এটি মান দ্বারা পাস না করে যদি না প্রশ্নে থাকা বস্তুটি কার্যকর না করে ICloneable(যা দৃশ্যত Listশ্রেণিটি না করে)।

এর অর্থ হ'ল এটি Listনিজেই অনুলিপি করে তবে তালিকার অভ্যন্তরীণ অবজেক্টগুলির উল্লেখগুলি একই থাকে; এটি হ'ল, পয়েন্টারগুলি মূল হিসাবে একই জিনিসগুলি রেফারেন্স করতে থাকবে List

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

আরও তথ্যের জন্য "পাসিং পরামিতি" সম্পর্কিত এই এমএসডিএন নিবন্ধ থেকে পাসিং রেফারেন্স-টাইপ প্যারামিটার বিভাগটি পড়ুন ।

স্ট্যাকওভারফ্লো থেকে "কীভাবে একটি জেনেরিক তালিকা ক্লোন করব" "কীভাবে একটি তালিকাটির গভীর অনুলিপি তৈরি করতে হবে তা সম্পর্কে আলোচনা করা হয়েছে।


3

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

এখানে আমার যুক্তি রয়েছে ... তালিকাটি রেফারেন্স দ্বারা পাস করা হলেও, এটি মান দ্বারা পয়েন্টার ভেরিয়েবল পাস করার কথা মনে করুন যখন আপনি চেঞ্জলিস্ট (মাইলিস্ট) কল করবেন আপনি পয়েন্টারটি (গ্লোবাল) মাইলিস্টে পাস করছেন। এখন এটি (স্থানীয়) মাইলিস্ট ভেরিয়েবলে সঞ্চিত রয়েছে। সুতরাং এখন আপনার (স্থানীয়) মাইলিস্ট এবং (গ্লোবাল) মাইলিস্ট একই তালিকার দিকে ইঙ্গিত করছে। এখন আপনি একটি বাছাই করুন => এটি কাজ করে কারণ (স্থানীয়) মাইলিস্টটি মূল (গ্লোবাল) মাইলিস্টকে উল্লেখ করছে পরবর্তী আপনি একটি নতুন তালিকা তৈরি করেন এবং আপনার (স্থানীয়) মাইলিস্টকে পয়েন্টার বরাদ্দ করেন। তবে ফাংশনটি প্রস্থান করার সাথে সাথেই (স্থানীয়) মাইলিস্ট ভেরিয়েবলটি নষ্ট হয়ে যায়। আছে HTH

class Test
{
    List<int> myList = new List<int>();
    public void TestMethod()
    {

        myList.Add(100);
        myList.Add(50);
        myList.Add(10);

        ChangeList();

        foreach (int i in myList)
        {
            Console.WriteLine(i);
        }
    }

    private void ChangeList()
    {
        myList.Sort();

        List<int> myList2 = new List<int>();
        myList2.Add(3);
        myList2.Add(4);

        myList = myList2;
    }
}

2

refকীওয়ার্ডটি ব্যবহার করুন ।

পাসিং প্যারামিটারগুলি বুঝতে এখানে নির্দিষ্ট রেফারেন্সটি দেখুন ।
নির্দিষ্ট, এ বর্ণন করা এই , কোড আচরণ বুঝতে।

সম্পাদনা: Sortএকই রেফারেন্সে কাজ করে (এটি মান দিয়ে পাস হয়) এবং তাই মানগুলি অর্ডার করা হয়। যাইহোক, প্যারামিটারে একটি নতুন উদাহরণ নির্ধারণ করা কার্যকর হবে না কারণ আপনি না রাখলে প্যারামিটারটি মান দ্বারা পাস হয় ref

লাগানো refআপনাকে Listআপনার ক্ষেত্রে নতুন দৃষ্টান্তের জন্য রেফারেন্সটিতে পয়েন্টার পরিবর্তন করতে দেয় । ছাড়া ref, আপনি বিদ্যমান প্যারামিটারে কাজ করতে পারেন, তবে এটি অন্য কোনও দিকে ইঙ্গিত করতে পারবেন না।


0

রেফারেন্স টাইপের কোনও অবজেক্টের জন্য মেমরির দুটি অংশ বরাদ্দ করা হয়। একটি স্ট্যাক এবং একটি গাদা। স্ট্যাকের অংশটি (ওরফে পয়েন্টার) হিপযুক্ত অংশের রেফারেন্স ধারণ করে - যেখানে প্রকৃত মানগুলি সংরক্ষণ করা হয়।

যখন রেফার কীওয়ার্ডটি ব্যবহার না করা হয়, তখন স্ট্যাকের অংশের একটি অনুলিপি তৈরি করা হয় এবং পদ্ধতিতে দেওয়া হয় - গাদাতে একই অংশের রেফারেন্স। সুতরাং আপনি যদি গাদা অংশে কিছু পরিবর্তন করেন তবে সেই পরিবর্তনটি স্থায়ী থাকবে। যদি আপনি অনুলিপি পয়েন্টারটি পরিবর্তন করেন - এটিকে গাদাতে অন্য জায়গায় উল্লেখ করার জন্য নির্ধারণ করে - এটি পদ্ধতির বাইরে উত্স পয়েন্টারকে প্রভাবিত করবে না।

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