সি # তে রেফারেন্স-টাইপ ভেরিয়েবলের জন্য "রেফ" ব্যবহার কী?


176

আমি বুঝতে পেরেছি যে আমি যদি প্যারামিটার হিসাবে কোনও মান-টাইপ ( int, structইত্যাদি) পাস করি ( refকীওয়ার্ড ব্যতীত), সেই ভেরিয়েবলের একটি অনুলিপি পদ্ধতিতে প্রেরণ করা হয় তবে আমি refকীওয়ার্ডটি ব্যবহার করি যদি সেই ভেরিয়েবলের একটি রেফারেন্স পাস হয়, নতুন নয়

কিন্তু রেফারেন্স-প্রকারের সাথে ক্লাসগুলির মতো refকীওয়ার্ড ছাড়াই রেফারেন্সটি কোনও কপি নয়, পদ্ধতিতে প্রেরণ করা হয়। তাহলে কী ref-ওয়ার্ডটি রেফারেন্স-টাইপ সহ ব্যবহার করবেন ?


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

var x = new Foo();

নীচের মধ্যে পার্থক্য কি?

void Bar(Foo y) {
    y.Name = "2";
}

এবং

void Bar(ref Foo y) {
    y.Name = "2";
}

উত্তর:


154

আপনি কী fooপয়েন্টগুলি ব্যবহার করে তা পরিবর্তন করতে পারেন y:

Foo foo = new Foo("1");

void Bar(ref Foo y)
{
    y = new Foo("2");
}

Bar(ref foo);
// foo.Name == "2"

17
সুতরাং আপনি
মূলসূত্রটির

2
আসল রেফারেন্সটি 'রেফারেন্স' বলতে আপনি যা পরিবর্তন করতে পারেন তাই হ্যাঁ।
ব্যবহারকারী 7116

1
ক্রিস, আপনার ব্যাখ্যা দুর্দান্ত; আমাকে এই ধারণাটি বুঝতে সহায়তা করার জন্য ধন্যবাদ।
Andreas গ্রেচ

4
সুতরাং কোনও সামগ্রীতে 'রেফ' ব্যবহার করা কি সি ++ এ ডাবল পয়েন্টার ব্যবহারের মতো?
টম হ্যাজেল

1
@ টমহাজেল: -শব্দ , আপনি সি ++ তে "ডাবল" পয়েন্টার ব্যবহার করছেন তবে পয়েন্টারটি কী নির্দেশ করবে?
ব্যবহারকারী 7116

29

এমন কেস রয়েছে যেখানে আপনি প্রকৃত রেফারেন্সটি পরিবর্তন করতে চান এবং অবজেক্টটি নির্দেশিত নয়:

void Swap<T>(ref T x, ref T y) {
    T t = x;
    x = y;
    y = t;
}

var test = new[] { "0", "1" };
Swap(ref test[0], ref test[1]);

21

জন স্কিটি সি # তে প্যারামিটার পাস করার বিষয়ে একটি দুর্দান্ত নিবন্ধ লিখেছিল । এটি মান দ্বারা, রেফারেন্স ( ref) দ্বারা এবং আউটপুট ( out) দ্বারা যথাযথভাবে পরামিতিগুলির সঠিক আচরণ এবং ব্যবহারের বিশদ বর্ণনা করে ।

refপরামিতিগুলির সাথে সম্পর্কিত সেই পৃষ্ঠা থেকে একটি গুরুত্বপূর্ণ উদ্ধৃতি এখানে :

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


11
আই-মান একটি রেফারেন্স পাশ করার জন্য বন্ধুকে আপনার কুকুর শিকল ক্ষণস্থায়ী উপমা মত ... এটা নিচে দ্রুত যদিও ভঙ্গ, কারণ আমি মনে করি আপনি would সম্ভবত নোটিশ যদি আপনার বন্ধু একটি doberman করার বানিজ্য-আপ আপনার shitzu আগেই তুমি ফিরে হস্তান্তর
ছিনতাই

16

এখানে খুব সুন্দরভাবে ব্যাখ্যা করা হয়েছে: http://msdn.microsoft.com/en-us/library/s6938f28.aspx

নিবন্ধ থেকে বিমূর্ত:

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


4
ব্যাখ্যাটি আসলে খুব সুন্দর। তবে লিঙ্ক-কেবল উত্তরগুলি এসও-তে নিরুৎসাহিত করা হয়েছে। আমি এখানে পাঠকদের সুবিধার্থে নিবন্ধ থেকে একটি সংক্ষিপ্তসার যুক্ত করেছি।
মার্সেল

10

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

সি # এর 'আউট' কীওয়ার্ডও রয়েছে যা অনেকটা রেফের মতো, 'রেফ' বাদে পদ্ধতিটি কল করার আগে আর্গুমেন্টগুলি শুরু করতে হবে এবং 'আউট' দিয়ে আপনাকে প্রাপ্তি পদ্ধতিতে একটি মান নির্ধারণ করতে হবে।


5

এটি আপনাকে পাস করা রেফারেন্সটি সংশোধন করতে দেয় eg যেমন

void Bar()
{
    var y = new Foo();
    Baz(ref y);
}

void Baz(ref Foo y)
{
    y.Name = "2";

    // Overwrite the reference
    y = new Foo();
}

আপনি যদি পাস রেফারেন্সটির বিষয়ে চিন্তা না করেন তবে আপনি এটি ব্যবহার করতে পারেন:

void Bar()
{
    var y = new Foo();
    Baz(out y);
}

void Baz(out Foo y)
{
    // Return a new reference
    y = new Foo();
}

4

কোড আরেকটি গুচ্ছ

class O
{
    public int prop = 0;
}

class Program
{
    static void Main(string[] args)
    {
        O o1 = new O();
        o1.prop = 1;

        O o2 = new O();
        o2.prop = 2;

        o1modifier(o1);
        o2modifier(ref o2);

        Console.WriteLine("1 : " + o1.prop.ToString());
        Console.WriteLine("2 : " + o2.prop.ToString());
        Console.ReadLine();
    }

    static void o1modifier(O o)
    {
        o = new O();
        o.prop = 3;
    }

    static void o2modifier(ref O o)
    {
        o = new O();
        o.prop = 4;
    }
}

3

বিদ্যমান উত্তরগুলি ছাড়াও:

আপনি যেমন 2 পদ্ধতির পার্থক্য জানতে চেয়েছিলেন: ব্যবহার করার সময় কোনও সহ (এনটিআর) বৈকল্পিক refবা নেই out:

class Foo { }
class FooBar : Foo { }

static void Bar(Foo foo) { }
static void Bar(ref Foo foo) { foo = new Foo(); }

void Main()
{
    Foo foo = null;
    Bar(foo);           // OK
    Bar(ref foo);       // OK

    FooBar fooBar = null;
    Bar(fooBar);        // OK (covariance)
    Bar(ref fooBar);    // compile time error
}

1

কোনও পদ্ধতির একটি প্যারামিটার মনে হয় সর্বদা একটি অনুলিপি পাস করছে, প্রশ্নটি কীসের একটি অনুলিপি। একটি অনুলিপি কোনও অনুলিপিটির জন্য অনুলিপি নির্মাণকারী দ্বারা করা হয় এবং যেহেতু সমস্ত ভেরিয়েবলগুলি সি # তে অবজেক্ট হয়, আমি বিশ্বাস করি এটি তাদের সকলের ক্ষেত্রে the ভেরিয়েবল (অবজেক্ট) হ'ল কিছু ঠিকানায় থাকা মানুষের মতো। আমরা হয় সেই ঠিকানাগুলিতে বসবাসকারী লোকদের পরিবর্তন করব অথবা ফোন বুকের সেই ঠিকানাগুলিতে বসবাসকারী লোকদের সম্পর্কে আমরা আরও রেফারেন্স তৈরি করতে পারি (অগভীর অনুলিপিগুলি তৈরি করতে পারি)। সুতরাং, একাধিক সনাক্তকারী একই ঠিকানাটি উল্লেখ করতে পারেন। রেফারেন্সের ধরণগুলি আরও স্থানের আকাঙ্ক্ষা করে, তাই স্ট্যাকের মধ্যে তাদের শনাক্তকারীর সাথে সরাসরি কোনও তীর দ্বারা সংযুক্ত এমন মানের ধরণের বিপরীতে তাদের স্তূপের অন্য কোনও ঠিকানার জন্য মূল্য রয়েছে (থাকার জন্য আরও বড় জায়গা)। এই স্থানটি গাদা থেকে নেওয়া দরকার।

মানের ধরণ: পরিচায়ক (স্ট্যাকের মানের ঠিকানা = ঠিকানা সহ) ----> মান ধরণের মান

রেফারেন্সের ধরণ: সনাক্তকারী অ্যারে [0], অ্যারে [1], অ্যারে [2] এর দিকে দিকনির্দেশ

মান পরিবর্তন করার একমাত্র উপায় হ'ল তীরগুলি অনুসরণ করা। যদি একটি তীর হারিয়ে যায় / পরিবর্তিত হয়ে যায় তবে মানটি অ্যাক্সেসযোগ্য।


-1

রেফারেন্স ভেরিয়েবলগুলি ঠিকানাটি এক জায়গা থেকে অন্য স্থানে নিয়ে যায় তাই কোনও স্থানে তাদের যে কোনও আপডেটের সমস্ত জায়গাগুলির প্রতিফলন ঘটবে তারপরে আরএফের ব্যবহার কী। পদ্ধতিতে পাস হওয়া রেফারেন্স ভেরিয়েবলটিতে কোনও নতুন মেমরি বরাদ্দ না হওয়া পর্যন্ত রেফারেন্স ভেরিয়েবল (405) ভাল।

একবার নতুন মেমরি বরাদ্দ (410) তারপরে এই বস্তুর মান পরিবর্তন (408) সর্বত্র প্রতিফলিত হবে না। এই রেফ জন্য আসে। রেফ রেফারেন্সের রেফারেন্স তাই যখনই নতুন মেমরি বরাদ্দ হয় এটি এটি জানতে কারণ এটি সেই অবস্থানটির দিকে নির্দেশ করছে তাই মানটি প্রত্যেকের দ্বারা ভাগ করা যায়। আপনি আরও পরিষ্কারতার জন্য চিত্রটি দেখতে পারেন।

রেফ ইন রেফারেন্স পরিবর্তনশীল

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