উত্তর:
একটি রেফারেন্স পাস হয়েছে; তবে, এটি প্রযুক্তিগতভাবে রেফারেন্স দ্বারা পাস করা হয়নি। এটি একটি সূক্ষ্ম, তবে খুব গুরুত্বপূর্ণ পার্থক্য। নিম্নলিখিত কোড বিবেচনা করুন:
void DoSomething(string strLocal)
{
strLocal = "local";
}
void Main()
{
string strMain = "main";
DoSomething(strMain);
Console.WriteLine(strMain); // What gets printed?
}
এখানে কী ঘটে তা বোঝার জন্য আপনার তিনটি জিনিস জানতে হবে:
strMain
দ্বারা পাস করা হয় না। এটি একটি রেফারেন্স টাইপ, তবে রেফারেন্সটি নিজেই মান দ্বারা পাস হয় । আপনি যে কোনও সময় ref
কীওয়ার্ড ছাড়াই প্যারামিটারটি পাস করেন ( out
প্যারামিটার গণনা করছে না ), আপনি মান দিয়ে কিছু পাস করেছেন।সুতরাং এর অর্থ অবশ্যই আপনি ... মান অনুসারে একটি রেফারেন্স পাস করছেন। এটি যেহেতু একটি রেফারেন্স টাইপ, কেবলমাত্র রেফারেন্সটি স্ট্যাকের অনুলিপি করা হয়েছিল। তবে তার মানে কী?
সি # ভেরিয়েবলগুলি হয় রেফারেন্স টাইপ বা মান ধরণের । সি # পরামিতি হয় হয় রেফারেন্স দ্বারা পাস হয় বা মান দ্বারা পাস হয় । পরিভাষা এখানে একটি সমস্যা; এই শব্দগুলি একই জিনিসটির মতো, তবে তারা তা নয়।
আপনি যদি কোনও প্রকারের প্যারামিটারটি পাস করেন এবং আপনি ref
কীওয়ার্ডটি ব্যবহার না করেন তবে আপনি এটি মান দিয়ে পাস করেছেন। যদি আপনি এটি মান দিয়ে পাস করেন তবে আপনি যা যা সত্যই পেরিয়েছেন তা ছিল একটি অনুলিপি। তবে যদি প্যারামিটারটি কোনও রেফারেন্স টাইপ হয়, তবে আপনি যে জিনিসটি অনুলিপি করেছেন সেটি হল রেফারেন্স, এটি যা দেখানো হয়েছিল তা নয়।
Main
পদ্ধতির প্রথম লাইনটি এখানে :
string strMain = "main";
আমরা এই লাইনে দুটি জিনিস তৈরি করেছি: main
কোথাও মেমরিতে সঞ্চিত মান সহ একটি স্ট্রিং , এবং strMain
এটি উল্লেখ করার জন্য একটি রেফারেন্স ভেরিয়েবল ।
DoSomething(strMain);
এখন আমরা সেই রেফারেন্সটি পাস করি DoSomething
। আমরা এটি মান দিয়ে পাস করেছি, এর অর্থ আমরা একটি অনুলিপি তৈরি করেছি। এটি একটি রেফারেন্সের ধরণ, সুতরাং এর অর্থ আমরা রেফারেন্সটি অনুলিপি করেছি, স্ট্রিংটি নয়। এখন আমাদের দুটি উল্লেখ রয়েছে যা প্রতিটি স্মৃতিতে একই মানের দিকে নির্দেশ করে।
DoSomething
পদ্ধতির শীর্ষস্থানীয় এখানে :
void DoSomething(string strLocal)
কোনও ref
কীওয়ার্ড নয়, তাই strLocal
এবং strMain
দুটি ভিন্ন রেফারেন্স একই মানের দিকে নির্দেশ করছে। আমরা যদি আবার নিয়োগ করি strLocal
...
strLocal = "local";
... আমরা সঞ্চিত মান পরিবর্তন করি নি; আমরা ফোন করা রেফারেন্সটি নিয়েছি এবং একে একে একে একে একে একে একে strLocal
নতুন নতুন স্ট্রিংয়ে রেখেছি। strMain
আমরা কি যখন কি ঘটবে ? কিছুই নেই। এটি এখনও পুরানো স্ট্রিংয়ের দিকে ইঙ্গিত করছে।
string strMain = "main"; // Store a string, create a reference to it
DoSomething(strMain); // Reference gets copied, copy gets re-pointed
Console.WriteLine(strMain); // The original string is still "main"
এক সেকেন্ডের জন্য দৃশ্যপট পরিবর্তন করা যাক। কল্পনা করুন আমরা স্ট্রিং নিয়ে কাজ করছি না, তবে আপনি তৈরি করেছেন এমন শ্রেণীর মতো কিছু পরিবর্তনীয় রেফারেন্স টাইপ।
class MutableThing
{
public int ChangeMe { get; set; }
}
আপনি যদি নির্দেশিত অবজেক্টের রেফারেন্সটি অনুসরণ করেন তবে আপনি objLocal
এর বৈশিষ্ট্যগুলি পরিবর্তন করতে পারেন:
void DoSomething(MutableThing objLocal)
{
objLocal.ChangeMe = 0;
}
MutableThing
স্মৃতিতে এখনও একটি মাত্র আছে , এবং অনুলিপি করা রেফারেন্স এবং মূল রেফারেন্স উভয়ই এখনও এটি দেখায়। নিজস্ব বৈশিষ্ট্যগুলি MutableThing
পরিবর্তিত হয়েছে :
void Main()
{
var objMain = new MutableThing();
objMain.ChangeMe = 5;
Console.WriteLine(objMain.ChangeMe); // it's 5 on objMain
DoSomething(objMain); // now it's 0 on objLocal
Console.WriteLine(objMain.ChangeMe); // it's also 0 on objMain
}
আহ, কিন্তু স্ট্রিং অবিচ্ছেদ্য! ChangeMe
সেট করার মতো কোনও সম্পত্তি নেই । আপনি strLocal[3] = 'H'
সি-স্টাইল char
অ্যারে দিয়ে যেমন করতে পারেন তেমন সি-তে পারবেন না ; পরিবর্তে আপনাকে একটি সম্পূর্ণ নতুন স্ট্রিং তৈরি করতে হবে। পরিবর্তনের একমাত্র উপায় strLocal
হ'ল রেফারেন্সটিকে অন্য স্ট্রিংয়ে দেখানো, এবং এর অর্থ আপনি strLocal
প্রভাবিত করতে পারে না এমন কিছুই strMain
। মান অপরিবর্তনীয় এবং রেফারেন্সটি একটি অনুলিপি।
পার্থক্য প্রমাণ করার জন্য, আপনি যখন রেফারেন্সের মাধ্যমে রেফারেন্সটি পাস করেন তখন কী হয় :
void DoSomethingByReference(ref string strLocal)
{
strLocal = "local";
}
void Main()
{
string strMain = "main";
DoSomethingByReference(ref strMain);
Console.WriteLine(strMain); // Prints "local"
}
এবার, স্ট্রিংটি Main
সত্যই পরিবর্তিত হবে কারণ আপনি স্ট্যাকে অনুলিপি না করে রেফারেন্সটি পাস করেছেন।
স্ট্রিংগুলি রেফারেন্সের ধরণের হলেও, মান দ্বারা সেগুলি পাস করার অর্থ যা ঘটে তা কলিতে যা হয় তা কলারের স্ট্রিংকে প্রভাবিত করে না। কিন্তু যেহেতু তারা হয় রেফারেন্স ধরনের, আপনি যখন আপনি এটি প্রায় পাস করতে চান মেমরি সমগ্র স্ট্রিং কপি করতে হবে না।
ref
। রেফারেন্স দ্বারা পাস করা একটি তাত্পর্যপূর্ণ
ref
কীওয়ার্ডটির ইউটিলিটি রয়েছে, আমি কেবল ব্যাখ্যা করার চেষ্টা করছিলাম যে কেন কেউ সি # তে মান অনুসারে রেফারেন্স টাইপ পাস করার কথা ভাবতে পারে কারণ "প্রথাগত" (যেমন সি) রেফারেন্স দিয়ে পাস করার মতামত (এবং একটি রেফারেন্স টাইপ পাস করার মত) মনে হচ্ছে সি # তে রেফারেন্স দ্বারা মান দ্বারা কোনও রেফারেন্সকে রেফারেন্স দেওয়ার মতো মনে হয়)।
Foo(string bar)
হিসাবে চিন্তা করা যেতে পারে Foo(char* bar)
যেহেতু Foo(ref string bar)
হবে Foo(char** bar)
(অথবা Foo(char*& bar)
বা Foo(string& bar)
C ++)। অবশ্যই, এটি আপনাকে প্রতিদিন কীভাবে ভাবা উচিত তা নয়, তবে এটি আসলে আমাকে হুডের নীচে কী ঘটছে তা বুঝতে সাহায্য করেছে।
সি # তে স্ট্রিংগুলি পরিবর্তনযোগ্য রেফারেন্স অবজেক্ট। এর অর্থ হ'ল তাদের কাছে উল্লেখগুলি (মান অনুসারে) প্রায় পাশ করা হয় এবং একবার স্ট্রিং তৈরি হয়ে গেলে আপনি এটিকে পরিবর্তন করতে পারবেন না। স্ট্রিংয়ের পরিবর্তিত সংস্করণগুলি তৈরি করার পদ্ধতিগুলি (সাবস্ট্রিংগুলি, ছাঁটাই করা সংস্করণগুলি ইত্যাদি) মূল স্ট্রিংয়ের পরিবর্তিত অনুলিপি তৈরি করে ।
স্ট্রিংগুলি বিশেষ ক্ষেত্রে। প্রতিটি উদাহরণ অপরিবর্তনীয়। আপনি যখন স্ট্রিংয়ের মান পরিবর্তন করেন আপনি মেমরিতে একটি নতুন স্ট্রিং বরাদ্দ করছেন।
সুতরাং কেবলমাত্র আপনার ফাংশনে রেফারেন্সটি প্রেরণ করা হবে তবে স্ট্রিংটি সম্পাদিত হয়ে গেলে এটি একটি নতুন উদাহরণ হয়ে যায় এবং পুরানো দৃষ্টান্তটি পরিবর্তন করে না।
Uri
(শ্রেণি) এবং Guid
( কাঠামোগত ) এছাড়াও বিশেষ ঘটনা। System.String
শ্রেণিবদ্ধ বা কাঠামো উত্পন্ন অন্য অপরিবর্তনীয় প্রকারের চেয়ে "মান টাইপ" এর মতো কীভাবে কাজ করে তা আমি দেখতে পাই না ।
Uri
& Guid
- আপনি অবশ্য একটি স্ট্রিং পরিবর্তনশীল করার জন্য একটি স্ট্রিং-আক্ষরিক মান ধার্য করতে পারেন। স্ট্রিংটি int
পুনঃনির্ধারিত হওয়ার মতো পরিবর্তিত হতে পারে বলে মনে হচ্ছে তবে এটি কোনও স্পষ্টতই কোনও বস্তু তৈরি করছে - কোনও new
কীওয়ার্ড নেই।