কেন আইসিএলনেবল নয় <টি>?


222

জেনেরিকের ICloneable<T>অস্তিত্ব না থাকার কোনও কারণ আছে কি ?

এটি অনেক বেশি স্বাচ্ছন্দ্যযুক্ত হবে, যদি প্রতিবার আমি কিছু ক্লোন করে ফেলার প্রয়োজন হয় না।


6
না! 'কারণগুলির' প্রতি যথাযথ সম্মান সহ, আমি আপনার সাথে একমত, তাদের এটি বাস্তবায়ন করা উচিত ছিল!
শিমি ওয়েটজ্যান্ডলার

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

এটি উপযুক্ত ক্লোনিং শ্রেণীর শ্রেণিবিন্যাসের অনুমতি দেবে, যেখানে উত্তরাধিকারসূত্রে প্রাপ্ত শ্রেণিগুলি সুরক্ষিত "ক্লোন" পদ্ধতিটি প্রকাশ করে এবং জনসাধারণকে উন্মোচিত করে এমন ডেরিভেটিভগুলিকে সীলমোহর করে দেয়। উদাহরণস্বরূপ, কারও কাছে পাইল, ক্লোনিয়েবল পাইল: পাইল, এনহ্যান্সেড পাইল: পাইল এবং ক্লোনিয়েবল এনহান্সড পাইল রয়েছে: এনহান্সড পাইল, যার কোনওটি ক্লোন করা থাকলেও ভাঙা যাবে না (যদিও সমস্ত পাবলিক ক্লোনিং পদ্ধতি প্রকাশ না করে), এবং আরও উন্নত পাইলে: এনহ্যান্সড পাইল (যা ভাঙ্গা হবে যদি ক্লোন করা থাকে তবে কোনও ক্লোনিং পদ্ধতি প্রকাশ করে না)। একটি রুটিন যে (গাদা) একজন ICloneable গ্রহণ একটি CloneablePile বা CloneableEnhancedPile ... গ্রহণ করতে পারে
supercat

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

উত্তর:


111

আইসিএলনেবলকে এখন একটি খারাপ এপিআই হিসাবে বিবেচনা করা হচ্ছে, কারণ ফলাফলটি গভীর বা অগভীর অনুলিপি কিনা তা নির্দিষ্ট করে না। আমি মনে করি এই কারণেই তারা এই ইন্টারফেসটির উন্নতি করে না।

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


8
আমি একমত নই, খারাপ বা খারাপ না, এটি শ্যালোন ক্লোনিংয়ের জন্য একসময় খুব দরকারী এবং সেই ক্ষেত্রে একটি অপ্রয়োজনীয় বক্সিং এবং আনবক্সিং বাঁচাতে সত্যিই ক্লোন <T> প্রয়োজন।
শিমি ওয়েটজ্যান্ডলার

2
@ অ্যান্ড্রে শ্যাচিন: গভীর বনাম অগভীর ক্লোনিং সম্পর্কে অস্পষ্টতা কী? যদি List<T>কোনও ক্লোন পদ্ধতি থাকে তবে আমি এটি প্রত্যাশা করবো List<T>যেগুলির আইটেমগুলির মূল তালিকার মতো একই পরিচয় রয়েছে তবে আমি আশা করব যে কোনও তালিকার কোনও কিছুই প্রভাবিত হবে না তা নিশ্চিত করার জন্য যে কোনও অভ্যন্তরীণ ডেটা স্ট্রাকচারগুলি নকল করা হবে ensure পরিচয় আইটেম অন্য সংরক্ষণ করা হয়। অস্পষ্টতা কোথায়? ক্লোনিংয়ের একটি বড় সমস্যা "হীরা সমস্যা" এর পরিবর্তনের সাথে আসে: যদি CloneableFoo[সর্বজনীনভাবে ক্লোনযোগ্য নয়] থেকে উত্তরাধিকার সূত্রে প্রাপ্ত হয় তবে তা থেকে প্রাপ্ত Fooহওয়া উচিত CloneableDerivedFoo...
সুপারক্যাট

1
@ সুপের্যাট: আমি বলতে পারি না আমি আপনার প্রত্যাশা পুরোপুরি বুঝতে পেরেছি, যেমন আপনি identityতালিকার একটিতে কী বিবেচনা করবেন , উদাহরণস্বরূপ (তালিকার তালিকার ক্ষেত্রে)? যাইহোক, যে উপেক্ষা, আপনার প্রত্যাশা না শুধুমাত্র সম্ভব ধারণা মানুষ যখন কল করা বা বাস্তবায়ন আছে পারে Clone। যদি অন্য কিছু তালিকা বাস্তবায়ন করে গ্রন্থাগারের লেখকরা আপনার প্রত্যাশা অনুসরণ না করে তবে কী হবে? এপিআইটি তুচ্ছভাবে দ্ব্যর্থহীন হওয়া উচিত, তর্কাতীতভাবে দ্ব্যর্থহীন নয়।
অ্যান্ড্রে শেকিন

2
@ সুপের্যাট তাই আপনি অগভীর অনুলিপি সম্পর্কে কথা বলছেন। তবে, একটি গভীর অনুলিপিতে মূলত ভুল কিছু নেই, উদাহরণস্বরূপ, যদি আপনি মেমরির অবজেক্টগুলিতে একটি বিপরীতমুখী লেনদেন করতে চান। আপনার প্রত্যাশা আপনার ব্যবহারের ক্ষেত্রে ভিত্তি করে, অন্য ব্যক্তির বিভিন্ন প্রত্যাশা থাকতে পারে। যদি তারা আপনার বস্তুগুলিকে তাদের বস্তুগুলিতে (বা বিপরীতে) রাখে তবে ফলাফল অপ্রত্যাশিত হবে।
অ্যান্ড্রে শেকিন

5
আপনি যে অ্যাকাউন্টটি গ্রাহ্য করেন না সেটিকে সুপারিশ করুন এটি NET ফ্রেমওয়ার্কের একটি অংশ, আপনার আবেদনের অংশ নয়। সুতরাং আপনি যদি এমন ক্লাস তৈরি করেন যা গভীর ক্লোনিং করে না, তবে অন্য কেউ এমন ক্লাস তৈরি করে যা গভীর ক্লোনিং করে এবং Cloneতার সমস্ত অংশগুলিতে কল করে, এটি পূর্বাভাসের সাথে কাজ করবে না - সেই অংশটি আপনার বা সেই ব্যক্তি দ্বারা প্রয়োগ করা হয়েছিল কিনা তার উপর নির্ভর করে যারা গভীর ক্লোনিং পছন্দ করেন। নিদর্শনগুলি সম্পর্কে আপনার বক্তব্য বৈধ তবে এপিআই-তে আইএমএইচএও থাকা যথেষ্ট স্পষ্ট নয় - এটি হয় ShallowCopyবিন্দুকে চাপ দেওয়ার জন্য বলা উচিত , বা আদৌ সরবরাহ করা হয়নি।
অ্যান্ড্রে শেকিন

141

আন্দ্রে উত্তর ছাড়াও (যা আমি একমত +1) - যখন ICloneable হয় কাজ, এছাড়াও আপনি স্পষ্ট বাস্তবায়ন পাবলিক করা চয়ন করতে পারেন Clone()আগমন একটি টাইপ বস্তু:

public Foo Clone() { /* your code */ }
object ICloneable.Clone() {return Clone();}

অবশ্যই জেনেরিক ICloneable<T>- উত্তরাধিকার নিয়ে দ্বিতীয় সমস্যা রয়েছে ।

যদি আমার থাকে:

public class Foo {}
public class Bar : Foo {}

এবং আমি বাস্তবায়ন করেছি ICloneable<T>, তাহলে আমি কি বাস্তবায়ন করব ICloneable<Foo>? ICloneable<Bar>? আপনি দ্রুত প্রচুর অভিন্ন ইন্টারফেস প্রয়োগ করতে শুরু করেছেন ... একটি কাস্টের সাথে তুলনা করুন ... এবং এটি কি এত খারাপ?


10
+1 আমি সর্বদা ভেবেছিলাম যে covariance সমস্যা হ'ল আসল কারণ
তামাস Czinege

এটির সাথে একটি সমস্যা রয়েছে: সুস্পষ্ট ইন্টারফেস বাস্তবায়নটি ব্যক্তিগত হতে হবে , যা সমস্যার কারণ হতে পারে এক পর্যায়ে ফু এর আইসিএলনেবলের কাছে কাস্ট করা দরকার ... আমি কি এখানে কিছু মিস করছি?
জোয়েল

3
আমার ভুল: এটা দেখা যাচ্ছে যে, ব্যক্তিগত হিসাবে সংজ্ঞায়িত হওয়া সত্ত্বেও পদ্ধতি হবে বলা যেতে ফু IClonable করার জন্য (CLR C # এর 2nd এড, p.319 মাধ্যমে) নিক্ষেপ করতে হবে। একটি বিজোড় নকশা সিদ্ধান্ত মত মনে হয়, কিন্তু এটি আছে। সুতরাং Foo.Clone () প্রথম পদ্ধতি দেয় এবং ((ICloneable) Foo) দেয় l ক্লোন () দ্বিতীয় পদ্ধতি দেয়।
জোল

প্রকৃতপক্ষে, স্পষ্টত ইন্টারফেস বাস্তবায়নগুলি কঠোরভাবে বলতে গেলে, জনসাধারণের API এর অংশ। এতে তারা কাস্টিংয়ের মাধ্যমে প্রকাশ্যে কলযোগ্য।
মার্ক গ্র্যাভেল

8
প্রস্তাবিত সমাধানটি প্রথমে দুর্দান্ত বলে মনে হচ্ছে ... যতক্ষণ না আপনি বুঝতে পেরেছেন যে কোনও শ্রেণি শ্রেণিবিন্যাসের মধ্যে আপনি 'পাবলিক ফু ক্লোন ()' ভার্চুয়াল হতে এবং উদ্ভূত শ্রেণিতে ওভাররাইড করতে চান যাতে তারা তাদের নিজস্ব ধরণটি ফিরে আসতে পারে (এবং তাদের নিজস্ব ক্ষেত্রগুলি ক্লোন করতে পারে) অবশ্যই)। দুঃখের বিষয়, আপনি ওভাররাইডে উল্লিখিত প্রকার পরিবর্তন করতে পারবেন না (উল্লিখিত কোভেরিয়েন্স সমস্যা) সুতরাং, আপনি আবার পুরো সমস্যার সাথে আবার আসল সমস্যার দিকে ফিরে আসবেন - সুস্পষ্ট বাস্তবায়ন আপনাকে সত্যিকার অর্থে অনেক বেশি কিনে না ('অবজেক্ট'-এর পরিবর্তে আপনার শ্রেণিবিন্যাসের বেসের ধরণটি ফেরানো ব্যতীত)) এবং আপনি আপনার বেশিরভাগ কাস্টিংয়ে ফিরে এসেছেন ক্লোন () কল ফলাফল। ইশ!
কেন বেকেট

18

আমার জিজ্ঞাসা করা দরকার, আপনি ইন্টারফেসটি বাস্তবায়ন ছাড়া অন্যটি দিয়ে ঠিক কী করবেন ? ইন্টারফেসগুলি কেবল তখনই কার্যকর হয় যখন আপনি এটিতে কাস্ট করেন (যেমন এই শ্রেণিটি 'আইবার' সমর্থন করে), বা প্যারামিটার বা সেটারগুলি রয়েছে যা এটি গ্রহণ করে (যেমন আমি একটি 'আইবার' নিই)। আইসিএলনেবলের সাথে - আমরা পুরো ফ্রেমওয়ার্কটি পেরিয়ে গিয়েছিলাম এবং এটির প্রয়োগ ব্যতীত অন্য কোনও কিছু ছিল এমন একক ব্যবহার সন্ধান করতে ব্যর্থ হয়েছি। আমরা 'বাস্তব বিশ্বে' এমন কোনও ব্যবহার সন্ধান করতেও ব্যর্থ হয়েছি যা এটিকে বাস্তবায়ন করা ছাড়াও অন্য কিছু করে (আমাদের যে ~ 60,000 অ্যাপ্লিকেশনটিতে অ্যাক্সেস রয়েছে)।

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

ডেভিড কেন (বিসিএল দল)


1
অ জেনেরিক ICloneable খুব দরকারী নয়, কিন্তু ICloneable<out T>বেশ উপযোগী হতে পারে যদি তা থেকে উত্তরাধিকারসূত্রে ISelf<out T>একটি একক পদ্ধতি সঙ্গে, Selfধরনের T। একজনের প্রায়শই "ক্লোনযোগ্য এমন কিছু" প্রয়োজন হয় না তবে ক্লোনযোগ্য এমন একটির খুব প্রয়োজন হতে পারে T। যদি কোনও ক্লোনযোগ্য অবজেক্ট প্রয়োগ করে ISelf<itsOwnType>, এমন একটি রুটিন যা Tক্লোনযোগ্য দরকার তার ধরণের একটি পরামিতি গ্রহণ করতে পারে ICloneable<T>, এমনকি যদি ক্লোনিয়েবল ডেরিভেটিভসগুলি Tএকটি সাধারণ পূর্বপুরুষের ভাগ না করে।
সুপারক্যাট

ধন্যবাদ। এটি উপরে বর্ণিত কাস্ট পরিস্থিতিগুলির সাথে সমান (যেমন 'এই শ্রেণিটি' আইবার 'সমর্থন করে)। দুঃখের বিষয়, আমরা কেবলমাত্র খুব সীমাবদ্ধ এবং বিচ্ছিন্ন পরিস্থিতি নিয়ে এসেছি যেখানে আপনি সত্যিকার অর্থে এই বিষয়টি ব্যবহার করতে পারবেন যে টি ক্লোনযোগ্য। আপনার কি মনে আছে পরিস্থিতি?
ডেভিড ক্যান

কখনও কখনও বিশ্রী হয়ে ওঠে এমন একটি জিনিস যা কোনও সংগ্রহের বিষয়বস্তুকে একটি মান হিসাবে দেখানোর কথা ভাবা হয় (যেমন আমি এখন সংগ্রহে থাকা আইটেমগুলির সেটটি পরে জানতে চাই) mut এর মতো কিছু এর ICloneable<T>জন্য কার্যকর হতে পারে, যদিও সমান্তরাল পরিবর্তনযোগ্য এবং অপরিবর্তনীয় শ্রেণি বজায় রাখার জন্য বিস্তৃত কাঠামো আরও সহায়ক হতে পারে। অন্য কথায়, কোড যা কোন ধরণের কী Fooরয়েছে তা দেখার প্রয়োজন কিন্তু এটির রূপান্তর করতে পারে না বা আশাও করে না যে এটি কখনও পরিবর্তিত হবে না IReadableFoo, যখন ...
সুপারক্যাট

... কোড যা বিষয়বস্তু রাখা চায় Fooএকটি ব্যবহার করতে পারে ImmutableFooনিপূণভাবে এটি একটি ব্যবহার করতে পারে চায় যে যখন কোড MutableFoo। যে কোনও ধরণের কোড দেওয়া IReadableFooকোডগুলি কোনও পরিবর্তনীয় বা অপরিবর্তনীয় সংস্করণ পেতে সক্ষম হওয়া উচিত। এই জাতীয় কাঠামো সুন্দর হবে তবে দুর্ভাগ্যক্রমে আমি জেনেরিক ফ্যাশনে জিনিস সেট আপ করার কোনও দুর্দান্ত উপায় খুঁজে পাচ্ছি না। কোনও শ্রেণীর জন্য কেবল পঠনযোগ্য মোড়ক তৈরির জন্য যদি ধারাবাহিক উপায় থাকে তবে এই জাতীয় জিনিসটি ICloneable<T>একটি শ্রেণীর একটি অনিবার্য অনুলিপি তৈরির সাথে মিশ্রণে ব্যবহার করা যেতে পারে T
সুপারক্যাট 5

@ সুপের্যাট যদি আপনি একটি ক্লোন করতে চান List<T>, যেমন ক্লোনন List<T>হ'ল একটি নতুন সংগ্রহ যা মূল সংগ্রহের একই সামগ্রীর সকলের জন্য পয়েন্টার রাখে, তা ছাড়া এটি করার দুটি সহজ উপায় রয়েছে ICloneable<T>। প্রথমটি হল Enumerable.ToList()এক্সটেনশন পদ্ধতি: List<foo> clone = original.ToList();দ্বিতীয়টি List<T>নির্মাণকারী যা গ্রহণ করে IEnumerable<T>: List<foo> clone = new List<foo>(original);আমার সন্দেহ হয় যে এক্সটেনশন পদ্ধতিটি সম্ভবত কেবল কনস্ট্রাক্টরকে কল করছে, তবে এই উভয়ই আপনি যা অনুরোধ করছেন তা করবে। ;)
CptRobi

12

আমি মনে করি "কেন" প্রশ্নটি অপ্রয়োজনীয়। এখানে অনেকগুলি ইন্টারফেস / ক্লাস / ইত্যাদি রয়েছে ... যা খুব দরকারী, তবে। নেট ফ্রেমওয়ার্কু বেস লাইব্রেরির অংশ নয়।

তবে, প্রধানত আপনি নিজেরাই এটি করতে পারেন।

public interface ICloneable<T> : ICloneable {
    new T Clone();
}

public abstract class CloneableBase<T> : ICloneable<T> where T : CloneableBase<T> {
    public abstract T Clone();
    object ICloneable.Clone() { return this.Clone(); }
}

public abstract class CloneableExBase<T> : CloneableBase<T> where T : CloneableExBase<T> {
    protected abstract T CreateClone();
    protected abstract void FillClone( T clone );
    public override T Clone() {
        T clone = this.CreateClone();
        if ( object.ReferenceEquals( clone, null ) ) { throw new NullReferenceException( "Clone was not created." ); }
        return clone
    }
}

public abstract class PersonBase<T> : CloneableExBase<T> where T : PersonBase<T> {
    public string Name { get; set; }

    protected override void FillClone( T clone ) {
        clone.Name = this.Name;
    }
}

public sealed class Person : PersonBase<Person> {
    protected override Person CreateClone() { return new Person(); }
}

public abstract class EmployeeBase<T> : PersonBase<T> where T : EmployeeBase<T> {
    public string Department { get; set; }

    protected override void FillClone( T clone ) {
        base.FillClone( clone );
        clone.Department = this.Department;
    }
}

public sealed class Employee : EmployeeBase<Employee> {
    protected override Employee CreateClone() { return new Employee(); }
}

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

@ সুপের্যাট কেন তখন এটিকে উত্তর দেবেন না?
নওফাল

"এখানে প্রচুর ইন্টারফেস / ক্লাস / ইত্যাদি রয়েছে ... যা খুব দরকারী, তবে। নেট ফ্রেমওয়ার্কু বেস লাইব্রেরির অংশ নয়।" আপনি আমাদের উদাহরণ দিতে পারেন?
ক্রিথিক

1
@ ক্রিথিক অর্থাত্: বি-ট্রি, লাল-কালো গাছ, চেনাশোনা বাফারের মতো উন্নত ডেটাস্ট্রাকচার '09-এ কোনও টিউপস, জেনেরিক দুর্বল-রেফারেন্স, সমবর্তী সংগ্রহগুলি ছিল না ...
TcKs

10

ইন্টারফেসটি প্রয়োজন হলে নিজেই লেখা খুব সহজ :

public interface ICloneable<T> : ICloneable
        where T : ICloneable<T>
{
    new T Clone();
}

কপিরাইট-
রসের

2
এবং ঠিক যে ইন্টারফেসটি কাজ করার কথা? টি টাইপ করার জন্য ক্লোন ক্রিয়াকলাপের ফলাফলের জন্য, ক্লোন করা বস্তুটি টি থেকে নেওয়া হয়েছিল type বাস্তবিকভাবে বলতে গেলে, কেবলমাত্র আইক্লোনেবল প্রত্যাবর্তনের ফলাফলটি আমি দেখতে পাচ্ছি তা হ'ল টাইপ আইক্লোনেবল।
সুপারক্যাট

@ সুপের্যাট: হ্যাঁ, ক্লোন () এটি ঠিক ফিরিয়ে দেয়: একটি টি যা আইক্লোনেবল <টি> প্রয়োগ করে। এমবিউনিত বছরের পর বছর ধরে এই ইন্টারফেসটি ব্যবহার করে আসছে , তাই হ্যাঁ, এটি কার্যকর হয়। বাস্তবায়নের জন্য, এমবিউনিতের উত্সটি দেখুন।
মৌরিসিও শেফার

2
@ মৌরিসিও শ্যাফার: আমি দেখছি কী চলছে। কোনও প্রকার আসলে আইক্লোনেবল (টি এর) প্রয়োগ করে না। পরিবর্তে, প্রতিটি প্রকার iCloneable (নিজেই) প্রয়োগ করে। এটি কাজ করবে, আমার ধারণা, যদিও এটি সমস্ত কিছু টাইপাস্টাস্ট সরিয়ে নেওয়া। এটি খুব খারাপ যে কোনও ক্ষেত্রকে উত্তরাধিকারের সীমাবদ্ধতা এবং একটি ইন্টারফেস হিসাবে ঘোষণা করার উপায় নেই; ক্লোনিং পদ্ধতিটি অর্ধ-ক্লোনযোগ্য (কেবল সুরক্ষিত পদ্ধতি হিসাবে প্রকাশিত ক্লোনিং) বেস ধরণের কোনও অবজেক্ট ফিরিয়ে আনতে সহায়ক হবে, তবে ক্লোনযোগ্য ধরণের সীমাবদ্ধতার সাথে। এটি কোনও অবজেক্টকে বেস ধরণের আধা-ক্লোনযোগ্য ডেরিভেটিভসের ক্লোনযোগ্য ডেরিভেটিভস গ্রহণ করতে অনুমতি দেয়।
সুপারক্যাট

@ মৌরিসিও শেফার: বিটিডাব্লু, আমি পরামর্শ দেব যে আইসি্লোনয়েবল (টি অফ) এছাড়াও একটি পঠনযোগ্য স্ব সম্পত্তি (রিটার্ন টাইপের টি) সমর্থন করবে। এটি কোনও পদ্ধতির মাধ্যমে আইসিলোনেবল (ফু এর) মেনে নেবে এবং এটিকে (স্ব সম্পত্তি হিসাবে) ফু হিসাবে ব্যবহার করবে।
supercat

8

সাম্প্রতিক নিবন্ধটি পড়ে কেন কোনও বস্তুর অনুলিপি করা একটি ভয়ঙ্কর কাজ? , আমি মনে করি এই প্রশ্নের অতিরিক্ত স্পেসিফিকেশন দরকার। এখানে অন্যান্য উত্তরগুলি ভাল পরামর্শ সরবরাহ করে, তবে এখনও উত্তরটি সম্পূর্ণ হয় না - কেন নয় ICloneable<T>?

  1. ব্যবহার

    সুতরাং, আপনার একটি ক্লাস রয়েছে যা এটি প্রয়োগ করে। পূর্বে আপনার কাছে এমন পদ্ধতি ছিল যা চেয়েছিল তবে ICloneableএটি এখন গ্রহণযোগ্য হতে হবে ICloneable<T>। আপনার এটি সম্পাদনা করতে হবে।

    তারপরে, আপনি একটি পদ্ধতি পেতে পারেন যা চেক করে কোনও বস্তু কিনা is ICloneable। এখন কি? আপনি করতে পারবেন না is ICloneable<>এবং যেহেতু আপনি কম্পাইল-টাইপে অবজেক্টের ধরণ জানেন না, আপনি পদ্ধতিটিকে জেনেরিক করতে পারবেন না। প্রথম আসল সমস্যা।

    সুতরাং আপনার উভয় ICloneable<T>এবং ICloneableপূর্ববর্তী পরবর্তী প্রয়োগকারী থাকা দরকার। সুতরাং একজন প্রয়োগকারীকে উভয় পদ্ধতি প্রয়োগ করতে হবে - object Clone()এবং T Clone()। না, ধন্যবাদ, ইতিমধ্যে আমরা যথেষ্ট মজা পেয়েছি IEnumerable

    ইতিমধ্যে চিহ্নিত হিসাবে, উত্তরাধিকার জটিলতাও রয়েছে। যদিও সমগোত্রীয়তা এই সমস্যার সমাধান করতে পারে বলে মনে হয়, একটি উদ্ভূত প্রকারের ICloneable<T>নিজস্ব ধরণের প্রয়োগ করতে হবে তবে ইতিমধ্যে একই স্বাক্ষরযুক্ত একটি পদ্ধতি রয়েছে (= পরামিতি, মূলত) - Clone()বেস শ্রেণীর। আপনার নতুন ক্লোন পদ্ধতির ইন্টারফেসটি সুস্পষ্ট করা অর্থহীন, আপনি তৈরি করার সময় আপনি যে সুবিধাটি চেয়েছিলেন তা হারাবেন ICloneable<T>। সুতরাং newকীওয়ার্ডটি যুক্ত করুন । তবে ভুলে যাবেন না যে আপনাকে বেস ক্লাসটি ওভাররাইড করা দরকার ' Clone()(বাস্তবায়নের জন্য সমস্ত উত্পন্ন শ্রেণীর জন্য অভিন্ন থাকতে হবে, অর্থাত্ প্রতিটি ক্লোন পদ্ধতি থেকে একই জিনিসটি ফিরে আসতে হবে, তাই বেস ক্লোন পদ্ধতিটিই হতে হবে virtual)! তবে, দুর্ভাগ্যক্রমে, আপনি overrideএবং উভয়ই পারেন নাnewএকই স্বাক্ষর সহ পদ্ধতি। প্রথম কীওয়ার্ডটি নির্বাচন করা, আপনি যুক্ত করার সময় আপনার যে লক্ষ্যটি চেয়েছিল তা হারাবেন ICloneable<T>। দ্বিতীয়টি বেছে নেওয়া, আপনি নিজেই ইন্টারফেসটি ভেঙে ফেলবেন, এমন পদ্ধতি তৈরি করে যাতে একই জিনিসটি বিভিন্ন বস্তুতে ফিরে আসে।

  2. বিন্দু

    আপনি ICloneable<T>স্বাচ্ছন্দ্যের জন্য চান , তবে স্বাচ্ছন্দ্যের জন্য ইন্টারফেসগুলি কীভাবে ডিজাইন করা হয়েছে তা নয়, এর অর্থ (সাধারণ ওওপিতে) অবজেক্টগুলির আচরণকে একত্রিত করার জন্য (যদিও সি # তে, এটি বাহ্যিক আচরণকে একত্রিত করার ক্ষেত্রে সীমাবদ্ধ, যেমন পদ্ধতি এবং বৈশিষ্ট্যগুলি নয়, তাদের কাজ)।

    যদি প্রথম কারণটি আপনাকে এখনও নিশ্চিত করে না, আপনি ICloneable<T>ক্লোন পদ্ধতি থেকে ফিরে আসা টাইপটিকে সীমাবদ্ধ করতে, এটি নিষিদ্ধভাবে কাজ করতে পারে এমন আপত্তিও করতে পারেন। তবে, দুষ্টু প্রোগ্রামার প্রয়োগ করতে পারে ICloneable<T>যেখানে টি প্রকারটি প্রয়োগ করে না। সুতরাং, আপনার সীমাবদ্ধতা অর্জনের জন্য, আপনি জেনেরিক প্যারামিটারে একটি দুর্দান্ত প্রতিবন্ধকতা যুক্ত করতে পারেন:
    public interface ICloneable<T> : ICloneable where T : ICloneable<T>
    নিশ্চিতভাবেই আরও বিধিনিষেধ ব্যতীত where, আপনি এখনও সীমাবদ্ধ করতে পারবেন না যে টি ইন্টারফেসটি কার্যকর করছে এমন ধরণটি (আপনি ICloneable<T>বিভিন্ন ধরণের থেকে প্রাপ্ত করতে পারেন) এটি প্রয়োগ করে)।

    আপনি দেখুন, এমনকি এই উদ্দেশ্য অর্জন করা যায়নি (আসলটিও ICloneableএতে ব্যর্থ হয়, কোনও ইন্টারফেস বাস্তবায়িত শ্রেণীর আচরণকে সীমাবদ্ধ করতে পারে না)।

আপনি দেখতে পাচ্ছেন যে, জেনেরিক ইন্টারফেসটিকে পুরোপুরি বাস্তবায়ন করা শক্ত এবং সত্যই অপ্রয়োজনীয় এবং অকেজো উভয়ই প্রমাণ করে।

তবে এই প্রশ্নটির দিকে ফিরে, আপনি কোন বিষয়টির ক্লোনিং করার সময় আরাম পাওয়া really এটি করার দুটি উপায় রয়েছে:

অতিরিক্ত পদ্ধতি

public class Base : ICloneable
{
    public Base Clone()
    {
        return this.CloneImpl() as Base;
    }

    object ICloneable.Clone()
    {
        return this.CloneImpl();
    }

    protected virtual object CloneImpl()
    {
        return new Base();
    }
}

public class Derived : Base
{
    public new Derived Clone()
    {
        return this.CloneImpl() as Derived;
    }

    protected override object CloneImpl()
    {
        return new Derived();
    }
}

এই সমাধানটি ব্যবহারকারীদের স্বাচ্ছন্দ্য এবং উদ্দেশ্যমূলক আচরণ উভয়ই সরবরাহ করে তবে এটি বাস্তবায়নের জন্যও এটি অনেক দীর্ঘ। যদি আমরা বর্তমানের ধরণটি ফিরিয়ে আনতে "আরামদায়ক" পদ্ধতিটি না নিতে চাই, তবে এটি ঠিক থাকা আরও অনেক সহজ public virtual object Clone()

তাহলে আসুন "চূড়ান্ত" সমাধানটি দেখুন - সি # তে আসলে কী আমাদের সান্ত্বনা দেওয়ার জন্য উদ্দিষ্ট?

এক্সটেনশন পদ্ধতি!

public class Base : ICloneable
{
    public virtual object Clone()
    {
        return new Base();
    }
}

public class Derived : Base
{
    public override object Clone()
    {
        return new Derived();
    }
}

public static T Copy<T>(this T obj) where T : class, ICloneable
{
    return obj.Clone() as T;
}

এটা তোলে নামে এর অনুলিপি বর্তমান সঙ্গে ধাক্কা লাগা না ক্লোন পদ্ধতি (কম্পাইলার এক্সটেনশন বেশী বেশী টাইপ নিজস্ব ঘোষিত পদ্ধতি পছন্দ করে)। classবাধ্যতা সেখানে গতির জন্য (পরীক্ষা নাল ইত্যাদি প্রয়োজন হয় না) হয়।

আমি আশা করি এটি কারণ না করার কারণ স্পষ্ট করে দেয় ICloneable<T>। তবে এটিকে বাস্তবায়ন না করার পরামর্শ দেওয়া হচ্ছে ICloneable


পরিসংখ্যান # 1: জেনেরিকের একমাত্র সম্ভাব্য ব্যবহার ICloneableমান ধরণের জন্য, যেখানে এটি ক্লোন পদ্ধতির বক্সিংটি বাধা দিতে পারে, এবং এটি ইঙ্গিত দেয় যে আপনার মানটি বাক্সবাক্সিত নয়। এবং কাঠামোগুলি স্বয়ংক্রিয়ভাবে ক্লোন করা যেতে পারে (অগভীরভাবে) তাই এটি কার্যকর করার দরকার নেই (যদি আপনি এটি নির্দিষ্ট করে না যে এটি গভীর অনুলিপি বোঝায়)।
ইলিডানএস 4 মনিকাকে

2

যদিও প্রশ্নটি খুব পুরানো (এই উত্তরগুলি লেখার 5 বছর :) :) এবং ইতিমধ্যে উত্তর দেওয়া হয়েছিল, তবে আমি এই নিবন্ধটি প্রশ্নের উত্তরটি বেশ ভালভাবে পেয়েছি, এটি এখানে দেখুন

সম্পাদনা করুন:

নিবন্ধটির উদ্ধৃতিটি এখানে প্রশ্নের উত্তর দিয়েছে (পুরো নিবন্ধটি পড়ার বিষয়টি নিশ্চিত করুন, এতে অন্যান্য আকর্ষণীয় বিষয় রয়েছে):

মাইক্রোসফ্টে নিযুক্ত সময়ে - ব্র্যাড আব্রামস দ্বারা 2003 সালে একটি ব্লগ পোস্টের দিকে ইঙ্গিত করে ইন্টারনেটে অনেকগুলি উল্লেখ রয়েছে - এতে আইক্লোনেবল সম্পর্কে কিছু চিন্তাভাবনা আলোচনা করা হয়েছে। ব্লগ এন্ট্রি এই ঠিকানায় পাওয়া যাবে: ICloneable বাস্তবায়ন । বিভ্রান্তকারী শিরোনাম সত্ত্বেও, এই ব্লগ এন্ট্রিটি মূলত অগভীর / গভীর বিভ্রান্তির কারণে ICloneable প্রয়োগ না করার আহ্বান জানায়। নিবন্ধটি একটি সরাসরি পরামর্শে শেষ হয়: আপনার যদি ক্লোনিং প্রক্রিয়া দরকার হয়, আপনার নিজের ক্লোন বা কপি পদ্ধতিটি সংজ্ঞায়িত করুন এবং নিশ্চিত করুন যে আপনি এটি গভীর বা অগভীর অনুলিপি কিনা তা স্পষ্টভাবে নথিভুক্ত করেছেন। একটি উপযুক্ত প্যাটার্ন হ'ল:public <type> Copy();


1

একটি বড় সমস্যা হ'ল তারা টি একই শ্রেণি হতে সীমাবদ্ধ করতে পারেনি। উদাহরণস্বরূপ যা আপনাকে এটি করতে বাধা দিতে পারে:

interface IClonable<T>
{
    T Clone();
}

class Dog : IClonable<JackRabbit>
{
    //not what you would expect, but possible
    JackRabbit Clone()
    {
        return new JackRabbit();
    }

}

তাদের যেমন প্যারামিটার সীমাবদ্ধতা প্রয়োজন:

interfact IClonable<T> where T : implementing_type

8
এটি class A : ICloneable { public object Clone() { return 1; } /* I can return whatever I want */ }
এতটা

সমস্যাটি আসলে কী তা আমি দেখছি না। কোনও ইন্টারফেস বাস্তবায়নকে যুক্তিসঙ্গত আচরণ করতে বাধ্য করতে পারে না। এমনকি যদি এটির নিজস্ব ধরণের সাথে মিলে ICloneable<T>যেতে বাধা সৃষ্টি Tকরতে পারে , তবে Clone()এটি ক্লোন করা বস্তুর সাথে সাদৃশ্যপূর্ণ কিছু প্রত্যাবর্তন করতে কোনও প্রয়োগকে বাধ্য করবে না । আরও, আমি প্রস্তাব দিচ্ছি যে যদি কেউ ইন্টারফেস covariance ব্যবহার করে থাকে তবে ক্লাসগুলি প্রয়োগ ICloneableকরা সিল করা ভাল হতে পারে , ইন্টারফেসটিতে ICloneable<out T>এমন একটি Selfসম্পত্তির অন্তর্ভুক্ত থাকতে হবে যা প্রত্যাশিত নিজেই ফিরে আসে, এবং ...
সুপারক্যাট

... নিক্ষেপ বা সীমাবদ্ধ ভোক্তাদের আছে ICloneable<BaseType>বা ICloneable<ICloneable<BaseType>>BaseTypeপ্রশ্নে একটি থাকতে হবে protectedক্লোনিং জন্য পদ্ধতি, যা টাইপ যা কার্যকরী ডাকা হবে ICloneable। এই নকশাটি এমন একটি সম্ভাবনার পক্ষে অনুমতি দেবে যে কেউ একটি Container, ক CloneableContainer, ক FancyContainerএবং CloneableFancyContainerক এর উত্তরোত্তর ব্যবহার করতে পারে যার ক্লোনযোগ্য ডেরাইভেটিভ Containerপ্রয়োজন হয় বা যার প্রয়োজন হয় FancyContainer(তবে এটি ক্লোনযোগ্য কিনা সেদিকে খেয়াল রাখে না)।
সুপারক্যাট

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

+1 - আমি এখানে যা দেখেছি তাদের থেকে এই উত্তরটিই একমাত্র যা সত্যই প্রশ্নের উত্তর দেয়।
ইলিডানএস

0

এটি একটি খুব ভাল প্রশ্ন ... আপনি নিজের তৈরি করতে পারেন, যদিও:

interface ICloneable<T> : ICloneable
{
  new T Clone ( );
}

আন্দ্রে বলছেন এটিকে একটি খারাপ এপিআই হিসাবে বিবেচনা করা হয়েছে, তবে আমি এই ইন্টারফেসটিকে হ্রাস করা সম্পর্কে কিছুই শুনিনি। এবং এটি বহু সংখ্যক ইন্টারফেস ভঙ্গ করবে ... ক্লোন পদ্ধতিটি একটি অগভীর অনুলিপি সম্পাদন করা উচিত। যদি বস্তুটি গভীর অনুলিপি সরবরাহ করে তবে একটি ওভারলোডেড ক্লোন (বুল গভীর) ব্যবহার করা যেতে পারে।

সম্পাদনা: প্যাটার্ন আমি কোনও বস্তুর "ক্লোনিং" করার জন্য ব্যবহার করি, কনস্ট্রাক্টরের মধ্যে একটি প্রোটোটাইপ পাস করে।

class C
{
  public C ( C prototype )
  {
    ...
  }
}

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


"খারাপ" এর অর্থ হতাশ নয়। এর সহজ অর্থ "আপনি এটি ব্যবহার না করাই ভাল" mean "আমরা ভবিষ্যতে ICloneable ইন্টারফেস অপসারণ করব" এই অর্থে এটিকে অবজ্ঞা করা হয়নি। তারা কেবল আপনাকে এটি ব্যবহার না করার জন্য উত্সাহ দেয়, এবং জেনেরিকগুলি বা অন্যান্য নতুন বৈশিষ্ট্য সহ এটি আপডেট করবে না।
জাল্ফ

ডেনিস: মার্কের উত্তর দেখুন। সাম্প্রদায়িকতা / উত্তরাধিকার সম্পর্কিত সমস্যাগুলি এই ইন্টারফেসটিকে কমপক্ষে প্রান্তিক জটিল যে কোনও দৃশ্যের জন্য বেশ ব্যবহারযোগ্য করে তোলে।
তামাস সিজনেজে

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