সি # তে জেনারিকের সাথে কোভেরিয়েন্সের বিপরীতে বোঝার সমস্যা


115

নীচের সি # কোড কেন সংকলন করছে না তা আমি বুঝতে পারি না।

আপনি দেখতে পাচ্ছেন, আমার কাছে একটি স্ট্যাটিক জেনেরিক পদ্ধতি রয়েছে একটি IEnumerable<T>প্যারামিটার সহ কিছু (এবং Tএটি একটি IAইন্টারফেস হতে বাধ্য হয় ), এবং এই পরামিতিটি স্পষ্টত রূপান্তরিত হতে পারে না IEnumerable<IA>

এর ব্যাখ্যা কী? (আমি কোনও কাজের জন্য অনুসন্ধান করি না, কেবল এটি কেন কাজ করে না তা বোঝার জন্য)।

public interface IA { }
public interface IB : IA { }
public class CIA : IA { }
public class CIAD : CIA { }
public class CIB : IB { }
public class CIBD : CIB { }

public static class Test
{
    public static IList<T> Something<T>(IEnumerable<T> foo) where T : IA
    {
        var bar = foo.ToList();

        // All those calls are legal
        Something2(new List<IA>());
        Something2(new List<IB>());
        Something2(new List<CIA>());
        Something2(new List<CIAD>());
        Something2(new List<CIB>());
        Something2(new List<CIBD>());
        Something2(bar.Cast<IA>());

        // This call is illegal
        Something2(bar);

        return bar;
    }

    private static void Something2(IEnumerable<IA> foo)
    {
    }
}

আমি Something2(bar)লাইন পেতে ত্রুটি :

আর্গুমেন্ট 1: 'সিস্টেম.কলেশনস.জেনারিক.লিস্ট' থেকে 'সিস্টেম.কলেশনস.জেনারিক.আইইনুমারেবল' তে রূপান্তর করতে পারে না



12
আপনি Tরেফারেন্স প্রকারের মধ্যে সীমাবদ্ধ করেননি । আপনি যদি শর্তটি ব্যবহার করেন where T: class, IAতবে এটি কাজ করা উচিত। লিঙ্কযুক্ত উত্তরে আরও বিশদ রয়েছে।
শির্ক

2
@ ডার্ক আমি মনে করি এটি নকল হিসাবে পতাকাঙ্কিত করা উচিত। যদিও এটি সত্য যে এখানে ধারণাগুলি সমস্যাটি মূল্য প্রকারের ক্ষেত্রে একটি সমবায় / বিপরীত সমস্যা, তবে এখানে নির্দিষ্ট ক্ষেত্রে "এই ত্রুটি বার্তাটি কী বোঝায়" পাশাপাশি লেখক কেবল "শ্রেণি" অন্তর্ভুক্ত করে বুঝতে পারছেন না যে তার সমস্যাটি সমাধান করে। আমি বিশ্বাস করি ভবিষ্যতের ব্যবহারকারীরা এই ত্রুটি বার্তাটি অনুসন্ধান করবে, এই পোস্টটি খুঁজে পাবে এবং খুশি হবে। (যেমনটি আমি প্রায়শই করি))
রেজিনাল্ড ব্লু

আপনি Something2(foo);সরাসরি সরাসরি বলে পরিস্থিতি পুনরুত্পাদন করতে পারেন । ( জেনেরিক পদ্ধতিতে আপনার টাইপ প্যারামিটারটি ঘোষিত) .ToList()পেতে কাছাকাছি যাওয়া ( এটিকে একটি ) বোঝার দরকার নেই । List<T>TList<T>IEnumerable<T>
জেপ্প স্টিগ নীলসেন

@ রেজিনাল্ড ব্লু 100%, একই জিনিস পোস্ট করা হয়। অনুরূপ উত্তরগুলি সদৃশ প্রশ্ন করে না।
ইউইউডিডিএলআরলিআরএস

উত্তর:


218

ত্রুটি বার্তাটি অপর্যাপ্ত তথ্যবহুল এবং এটি আমার দোষ। এর জন্যে দুঃখিত.

আপনি যে সমস্যার মুখোমুখি হচ্ছেন তা হ'ল সম্প্রদায়টি কেবল রেফারেন্সের ধরণের ক্ষেত্রে কাজ করে।

আপনি সম্ভবত "এখন কিন্তু IAএকটি রেফারেন্স টাইপ" বলছেন । হ্যাঁ, তাই তবে আপনি T এটি সমান বলে নি IA। আপনি বলেছিলেন যে এটি Tএমন এক প্রকার যা প্রয়োগ করে IA এবং একটি মান ধরণ একটি ইন্টারফেস প্রয়োগ করতে পারে । অতএব আমরা জানি না যে সমবায় কাজ করবে কিনা এবং আমরা তা অস্বীকার করি।

আপনি যদি কাজটি করতে সমবায় চান তবে আপনাকে সংকলকটি বলতে হবে যে টাইপ পরামিতিটি একটি classসীমাবদ্ধতার পাশাপাশি IAইন্টারফেসের সীমাবদ্ধতার সাথে একটি রেফারেন্স টাইপ ।

ত্রুটি বার্তায় সত্যই বলা উচিত যে রূপান্তর সম্ভব নয় কারণ সমবায়িকতার জন্য রেফারেন্স-টাইপ-নেসের গ্যারান্টি প্রয়োজন, যেহেতু এটিই মূল সমস্যা।


3
তুমি কেন বললে এটা তোমার দোষ?
user4951

77
@ user4951: কারণ আমি ত্রুটি বার্তাগুলি সহ সমস্ত রূপান্তর পরীক্ষার যুক্তি প্রয়োগ করেছি।
এরিক লিপার্ট

@ বার্নসবিএ কার্যকারণার্থে এটি কেবল একটি "দোষ" - প্রযুক্তিগতভাবে প্রয়োগের পাশাপাশি ত্রুটির বার্তাটি পুরোপুরি সঠিক। (এটি ঠিক যে অবান্তরতার ত্রুটি বিবৃতিটি প্রকৃত কারণগুলিতে বিস্তৃত হতে পারে But তবে জেনারিকের সাথে ভাল ত্রুটিগুলি উত্পন্ন করা কঠিন - কয়েক বছর আগে সি ++ টেম্পলেট ত্রুটির বার্তাগুলির তুলনায় এটি আকর্ষণীয় এবং সংক্ষিপ্ত))
পিটার - পুনর্নির্ধারণ মনিকা

3
@ পিটারএ.স্নাইডার: আমি এটির প্রশংসা করি। তবে রোজলিনে ত্রুটি রিপোর্টিংয়ের যুক্তি ডিজাইনের জন্য আমার প্রাথমিক লক্ষ্যগুলির মধ্যে একটি বিশেষত কেবলমাত্র কোন বিধি লঙ্ঘন করা হয়েছিল তা নয়, তবুও যেখানে সম্ভব সেখানে "মূল কারণ" চিহ্নিত করা ছিল। উদাহরণস্বরূপ, ত্রুটি বার্তাটি কীসের জন্য হওয়া উচিত customers.Select(c=>c.FristName)? সি # স্পেসিফিকেশনটি খুব স্পষ্ট যে এটি একটি ওভারলোড রেজোলিউশন ত্রুটি: প্রযোজ্য পদ্ধতির নাম সেট নির্বাচন করুন যা সেই ল্যাম্বডাকে ফাঁকা নিতে পারে। তবে এর মূল কারণটি FirstNameএকটি টাইপো রয়েছে।
এরিক লিপার্ট

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

26

আমি কেবল এরিকের দুর্দান্ত অভ্যন্তরীণ উত্তরটির জন্য একটি কোড উদাহরণ দিয়ে পরিপূরক করতে চেয়েছিলাম যারা জেনেরিক সীমাবদ্ধতার সাথে পরিচিত হতে পারে না।

Somethingএর স্বাক্ষরটি এভাবে পরিবর্তন করুন : classসীমাবদ্ধতাটি প্রথমে আসতে হবে

public static IList<T> Something<T>(IEnumerable<T> foo) where T : class, IA

2
আমি কৌতূহলী ... অর্ডারটির তাৎপর্যের পিছনে কারণ কী?
টম রাইট

5
@ টম রাইট - অনুমানটি অবশ্যই অনেকের উত্তর অন্তর্ভুক্ত করে না "কেন?" প্রশ্নগুলি, তবে এই ক্ষেত্রে এটি স্পষ্ট করে দেয় যে তিনটি স্বতন্ত্র ধরণের প্রতিবন্ধকতা রয়েছে এবং যখন তিনটি ব্যবহার করা হয় তখন তাদের নির্দিষ্টভাবে থাকতে হবেprimary_constraint ',' secondary_constraints ',' constructor_constraint
দামিয়েন_তে_বিশ্বাসীরা

2
@ টম রাইট: ড্যামিয়েন সঠিক; পার্সারের লেখকের সুবিধার্থে আমি অন্য কোনও বিষয়ে সচেতন সেটির কোনও কারণ নেই। আমার ড্রথার যদি টাইপ সীমাবদ্ধতার জন্য সিনট্যাক্স হয় তবে তা আরও বেশি ভার্জোজ ছিল। classখারাপ কারণ এটি "শ্রেণি" নয়, এর অর্থ "রেফারেন্স টাইপ"। আমি Verbose এর মতো কিছু নিয়ে আরও খুশি হতামwhere T is not struct
এরিক লিপার্ট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.