একটি তালিকা <এক্স> থেকে কোনও তালিকায় <Y> কাস্টিংয়ের জন্য সংক্ষিপ্ত বাক্য গঠন?


237

আমি জানি যে একরকম থেকে অন্য ধরণের আইটেমের তালিকা castালাই করা সম্ভব (আপনার অবজেক্টে ingালাই করার জন্য পাবলিক স্ট্যাটিক স্পষ্ট বর্ণিত অপারেটর পদ্ধতি রয়েছে) এক বারে একবারে:

List<Y> ListOfY = new List<Y>();

foreach(X x in ListOfX)
    ListOfY.Add((Y)x);

তবে পুরো তালিকাটি একবারে কাস্ট করা সম্ভব নয় কি? উদাহরণ স্বরূপ,

ListOfY = (List<Y>)ListOfX;

@ ওজেড: আমি এটিকে আরও পরিষ্কার করার চেষ্টা করেছি। চিন্তা করবেন না, আপনি নন, আমি বুঝতে পেরেছি :)
বোল্টক্লক

1
এক্স এর অনুমান Y থেকে প্রাপ্ত এবং জে Y থেকে প্রাপ্ত, ভাবেন আপনি কী করবেন যদি আপনার তালিকায় <Y> যা আসলেই একটি তালিকা <x> to
রিচার্ড ফ্রেন্ড

উত্তর:


497

যদি Xসত্যিই আপনার কাছে কাস্ট করা যায় তবে Yআপনি ব্যবহার করতে সক্ষম হবেন

List<Y> listOfY = listOfX.Cast<Y>().ToList();

কিছু বিষয় সচেতন হতে হবে (মন্তব্যকারীদের কাছে এইচ / টি)

  • using System.Linq;এই এক্সটেনশন পদ্ধতিটি পেতে আপনাকে অবশ্যই অন্তর্ভুক্ত করতে হবে
  • এটি তালিকার প্রতিটি আইটেমকে কাস্ট করে - তালিকাটি নিজেই নয়। List<Y>কল করে একটি নতুন তৈরি করা হবে ToList()
  • এই পদ্ধতিটি কাস্টম রূপান্তর অপারেটরদের সমর্থন করে না। (দেখুন http://stackoverflow.com/questions/14523530/why-does-the-linq-cast-helper-not- work-with-thelpimp-cast-operator )
  • এই পদ্ধতিটি এমন কোনও অবজেক্টের পক্ষে কাজ করে না যা স্পষ্টভাবে অপারেটর পদ্ধতিতে রয়েছে (ফ্রেমওয়ার্ক 4.0)

12
আরেকটি সোনার ব্যাজ রাখুন। এটি বেশ কার্যকর ছিল।
আউটফ্ল্যাক করুন

6
এই এক্সটেনশন পদ্ধতিগুলি সনাক্ত করতে সংকলকটি পেতে নিম্নলিখিত লাইনটি অবশ্যই অন্তর্ভুক্ত করতে হবে: System.Linq ব্যবহার করে;
হাইফিউম্যান

8
এছাড়াও সচেতন থাকুন যে এটি তালিকায় প্রতিটি আইটেমকে কাস্ট করে, তবে তালিকাটি নিজেই কাস্ট করা হয়নি; বরং পছন্দসই ধরণের সাথে একটি নতুন তালিকা তৈরি করা হয়।
হাইপুমান

4
এছাড়াও সচেতন হন যে Cast<T>পদ্ধতিটি কাস্টম রূপান্তর অপারেটরদের সমর্থন করে না। কেন লিঙ্ক কাস্ট সাহায্যকারী অন্তর্ভুক্ত কাস্ট অপারেটরের সাথে কাজ করে না
clD

এটি স্পষ্টত অপারেটর পদ্ধতি (ফ্রেমওয়ার্ক 4.0) রয়েছে এমন কোনও অবজেক্টের পক্ষে কাজ করে না
অ্যাড্রিয়ান

100

সরাসরি cast ালাইvar ListOfY = (List<Y>)ListOfX সম্ভব নয় কারণ এটির সাথে সহ / বিপরীতের দরকার হয় List<T>এবং এটি প্রতিটি ক্ষেত্রেই গ্যারান্টিযুক্ত হতে পারে না। এই castালাই সমস্যার সমাধান দেখতে দয়া করে পড়ুন।

যদিও এই জাতীয় কোড লিখতে পারাটা স্বাভাবিক বলে মনে হচ্ছে:

List<Animal> animals = (List<Animal>) mammalList;

কারণ আমরা গ্যারান্টি দিতে পারি যে প্রতিটি স্তন্যপায়ী প্রাণী একটি প্রাণী হবে, এটি স্পষ্টতই একটি ভুল:

List<Mammal> mammals = (List<Mammal>) animalList;

যেহেতু প্রতিটি প্রাণী একটি স্তন্যপায়ী প্রাণী নয়।

তবে, সি # 3 এবং তদূর্ধের ব্যবহার করে আপনি ব্যবহার করতে পারেন

IEnumerable<Animal> animals = mammalList.Cast<Animal>();

যা কিছুটা কাস্টিংকে সহজ করে দেয়। এটি সিনট্যাকটিকভাবে আপনার এক-এক করে সংযোজন কোডের সমতুল্য, কারণ এটি Mammalতালিকাতে প্রতিটিকে কাস্ট করার জন্য একটি স্পষ্ট কাস্ট ব্যবহার করে Animalএবং কাস্টটি সফল না হলে ব্যর্থ হবে।

আপনি যদি কাস্টিং / রূপান্তর প্রক্রিয়াটির উপর আরও নিয়ন্ত্রণ চান তবে আপনি ক্লাসের ConvertAllপদ্ধতিটি List<T>ব্যবহার করতে পারেন যা আইটেমগুলিতে রূপান্তর করতে সরবরাহিত এক্সপ্রেশন ব্যবহার করতে পারে। এটির সাথে যুক্ত বেনিফিট রয়েছে যে এটি Listপরিবর্তে একটি প্রদান করে IEnumerable, তাই কোনও .ToList()প্রয়োজন নেই।

List<object> o = new List<object>();
o.Add("one");
o.Add("two");
o.Add(3);

IEnumerable<string> s1 = o.Cast<string>(); //fails on the 3rd item
List<string> s2 = o.ConvertAll(x => x.ToString()); //succeeds

2
আমি বিশ্বাস করতে পারি না ive এখন পর্যন্ত এই উত্তরটি +1 করিনি। এটি আমার উপরের চেয়ে অনেক ভাল।
জামেখ

6
@ জামেখ আমি +1 করিনি কারণ তিনি "না, এটি সম্ভব নয়" দিয়ে শুরু করেছিলেন, উত্তরটি কবর দেওয়ার সময় যারা এই প্রশ্নটি সন্ধান করেন তাদের সন্ধান করছেন। প্রযুক্তিগতভাবে, তিনি ওপির প্রশ্নের উত্তর আরও পুঙ্খানুপুঙ্খভাবে দিয়েছিলেন।
ড্যান বেচার্ড

13

সুইকের বক্তব্য যুক্ত করতে:

কারণ কেন castালাই

var listOfX = new List<X>();
ListOf<Y> ys = (List<Y>)listOfX; // Compile error: Cannot implicitly cast X to Y

সম্ভব নয় কারণ List<T>হল প্রকার টি মধ্যে পরিবর্তিত এবং এইভাবে এটি কিনা কোন ব্যাপার না Xথেকে আহরিত Y) - এর কারণ List<T>হিসেবে সংজ্ঞায়িত করা হয়:

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T> ... // Other interfaces

(দ্রষ্টব্য যে এই ঘোষণাপত্রে, Tএখানে টাইপ করুন কোনও অতিরিক্ত বৈকল্পিক সংশোধক নেই)

তবে আপনার ডিজাইনে যদি পরিবর্তনীয় সংগ্রহের প্রয়োজন হয় না, তবে অনেকগুলি অপরিবর্তনীয় সংগ্রহের উপরে একটি আপকাস্ট সম্ভব , যেমন প্রদত্ত যেগুলি Giraffeথেকে প্রাপ্ত Animal:

IEnumerable<Animal> animals = giraffes;

এটি কারণে IEnumerable<T>কোভেরিয়েন্সকে সমর্থন করে T- এটি এই অর্থে IEnumerableবোঝায় যে এই সংগ্রহটি পরিবর্তন করা যায় না, যেহেতু সংগ্রহ থেকে উপাদানগুলি যুক্ত বা সরানোর পদ্ধতিগুলির কোনও সমর্থন নেই। outএর ঘোষণায় কীওয়ার্ডটি নোট করুন IEnumerable<T>:

public interface IEnumerable<out T> : IEnumerable

( কেন পরিবর্তনীয় সংগ্রহগুলি যেমন সমর্থন করতে পারে না তার কারণের জন্য এখানে আরও ব্যাখ্যা দেওয়া হয়েছে , যেখানে অপরিবর্তনীয় পুনরাবৃত্তকারী এবং সংগ্রহগুলি পারে))Listcovariance

সাথে কাস্টিং .Cast<T>()

অন্যরা যেমন উল্লেখ করেছে, .Cast<T>()টি তে নষ্ট হওয়া উপাদানগুলির একটি নতুন সংগ্রহের প্রকল্পের জন্য কোনও সংকলনের ক্ষেত্রে প্রয়োগ করা যেতে পারে, তবে এটি করার ফলে InvalidCastExceptionএক বা একাধিক উপাদানের উপর castালাই সম্ভব না হলে (যা স্পষ্ট করে দেওয়ার মতো আচরণ হবে) ওপির foreachলুপে কাস্ট করুন )।

ফিল্টারিং এবং সাথে কাস্টিং OfType<T>()

যদি ইনপুট তালিকায় বিভিন্ন, incompatable ধরণের উপাদান থাকে তবে এর পরিবর্তে InvalidCastExceptionব্যবহার করে সম্ভাব্যতা এড়ানো যায় । ( রূপান্তর করার চেষ্টা করার আগে কোনও উপাদানকে টার্গেটের ধরণের রূপান্তর করা যায় কিনা তা পরীক্ষা করে দেখুন এবং অবিচ্ছিন্ন প্রকারের ফিল্টার আউট করতে পারেন)).OfType<T>().Cast<T>().OfType<>()

প্রতিটির জন্য

এছাড়াও মনে রাখবেন যদি ওপি পরিবর্তে লিখেছিলাম: (নোট স্পষ্টY y মধ্যে foreach)

List<Y> ListOfY = new List<Y>();

foreach(Y y in ListOfX)
{
    ListOfY.Add(y);
}

theালাইও চেষ্টা করা হবে যে। তবে, যদি কোনও কাস্ট সম্ভব না হয় তবে একটি InvalidCastExceptionফলাফল হবে result

উদাহরণ

উদাহরণস্বরূপ, সরল (সি # 6) শ্রেণি শ্রেণিবিন্যাস দেওয়া হয়েছে:

public abstract class Animal
{
    public string Name { get;  }
    protected Animal(string name) { Name = name; }
}

public class Elephant :  Animal
{
    public Elephant(string name) : base(name){}
}

public class Zebra : Animal
{
    public Zebra(string name)  : base(name) { }
}

মিশ্র প্রকারের সংগ্রহের সাথে কাজ করার সময়:

var mixedAnimals = new Animal[]
{
    new Zebra("Zed"),
    new Elephant("Ellie")
};

foreach(Animal animal in mixedAnimals)
{
     // Fails for Zed - `InvalidCastException - cannot cast from Zebra to Elephant`
     castedAnimals.Add((Elephant)animal);
}

var castedAnimals = mixedAnimals.Cast<Elephant>()
    // Also fails for Zed with `InvalidCastException
    .ToList();

যেখানে:

var castedAnimals = mixedAnimals.OfType<Elephant>()
    .ToList();
// Ellie

কেবলমাত্র হাতিগুলিকে ফিল্টার করে - অর্থাত্ জেব্রাগুলি মুছে ফেলা হয়।

পুনরায়: অন্তর্ভুক্ত কাস্ট অপারেটররা

ডায়নামিক ব্যতীত, ব্যবহারকারী সংজ্ঞায়িত রূপান্তর অপারেটরগুলি কেবল সংকলন সময় * এ ব্যবহৃত হয় , সুতরাং জেব্রা এবং এলিফ্যান্টের মধ্যে রূপান্তরকারী অপারেটরটি উপলব্ধ করা হলেও, রূপান্তরকরণের পদ্ধতির উপরের রান টাইম আচরণটি পরিবর্তিত হবে না।

যদি আমরা একটি জেব্রাটিকে একটি এলিফ্যান্টে রূপান্তর করতে কোনও রূপান্তর অপারেটর যুক্ত করি:

public class Zebra : Animal
{
    public Zebra(string name) : base(name) { }
    public static implicit operator Elephant(Zebra z)
    {
        return new Elephant(z.Name);
    }
}

পরিবর্তে, উপরে রূপান্তর অপারেটর দেওয়া কম্পাইলার অ্যারের নীচের থেকে ধরণ পরিবর্তন করতে সক্ষম হবে Animal[]থেকে Elephant[]দেওয়া যে Zebras এখন হাতি একটি সজাতি সংগ্রহ রূপান্তরিত করা যেতে পারে:

var compilerInferredAnimals = new []
{
    new Zebra("Zed"),
    new Elephant("Ellie")
};

রান সময় ইম্পিলেটিভ রূপান্তর অপারেটর ব্যবহার

* এরিকের হিসাবে উল্লেখ করা হয়েছে, রূপান্তর অপারেটর অবশ্য চালুর সময় অবলম্বন করে অ্যাক্সেস করা যেতে পারে dynamic:

var mixedAnimals = new Animal[] // i.e. Polymorphic collection
{
    new Zebra("Zed"),
    new Elephant("Ellie")
};

foreach (dynamic animal in mixedAnimals)
{
    castedAnimals.Add(animal);
}
// Returns Zed, Ellie

আরে, আমি কেবল "ফিল্টারিং টাইপ ফিল্টারিংয়ের জন্য" ভবিষ্যত ব্যবহার () ব্যবহার করে উদাহরণটি ব্যবহার করে দেখেছি: var list = new list <object> () {1, "a", 2, "b", 3, "c", 4, " d "}; foreach (আমি তালিকায় IN) কনসোল.উরাইটলাইন (i); এবং আমি যখন এটি চালনা করি তখনই পাই "নির্দিষ্ট কাস্টটি বৈধ নয়।" আমি কিছু অনুপস্থিত করছি? আমি ভাবি নি ফোরচ এইভাবে কাজ করেছে, সে কারণেই আমি এটি চেষ্টা করেছিলাম।
ব্রেন্ট রাইটেনহাউস

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

ধন্যবাদ ব্রেন্ট - আমি সেখানে ছিলাম foreachফিল্টার করে না, তবে পুনরাবৃত্তকরণ ভেরিয়েবল হিসাবে আরও উদ্ভূত প্রকারটি ব্যবহার করা সংকলককে একটি কাস্ট চেষ্টা করার জন্য বাধ্য করবে, যা প্রথম উপাদানটিতে ব্যর্থ হবে যা মেনে চলে না।
স্টুয়ার্টলসি 22'18


3

এটি এই প্রশ্নের পুরোপুরি উত্তর নয়, তবে এটি কারওর পক্ষে কার্যকর হতে পারে: @ এসকিও বলেছিলেন যে, সম্প্রদায় এবং বিপরীতে ধন্যবাদ দেওয়া List<X>যেতে পারে না List<Y>, তবে List<X>তাকে নিক্ষেপ করা যায় না IEnumerable<Y>এবং এমনকি অন্তর্নিহিত কাস্ট দিয়েও।

উদাহরণ:

List<Y> ListOfY = new List<Y>();
List<X> ListOfX = (List<X>)ListOfY; // Compile error

কিন্তু

List<Y> ListOfY = new List<Y>();
IEnumerable<X> EnumerableOfX = ListOfY;  // No issue

বড় সুবিধাটি হ'ল এটি মেমরিতে নতুন তালিকা তৈরি করে না।


1
আমি এটি পছন্দ করি কারণ আপনার যদি একটি বৃহত উত্সের তালিকা থাকে তবে শুরুতে কোনও পারফরম্যান্স হিট হয় না। পরিবর্তে রিসিভারের দ্বারা প্রতিটি প্রবেশের প্রক্রিয়াজাতকরণের জন্য একটি ছোট নয় উল্লেখযোগ্য কাস্ট রয়েছে। এছাড়াও কোন বিশাল মেমরি আপ আপ। প্রবাহ প্রক্রিয়াকরণের জন্য নিখুঁত।
জোহান ফ্রানজান

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