সি # জেনেরিক পদ্ধতি নির্বাচন


9

আমি সি # তে জেনেরিক অ্যালগরিদমগুলি লেখার চেষ্টা করছি যা বিভিন্ন মাত্রার জ্যামিতিক সত্তার সাথে কাজ করতে পারে।

নীচের স্বীকৃত উদাহরণে আমার কাছে Point2এবং Point3উভয়ই একটি সাধারণ IPointইন্টারফেস প্রয়োগ করে ।

এখন আমি একটি ফাংশন GenericAlgorithmযা একটি ফাংশন কল GetDim। প্রকারের ভিত্তিতে এই ফাংশনের একাধিক সংজ্ঞা রয়েছে। ফলস-ব্যাক ফাংশনও রয়েছে যা প্রয়োগকারী কোনও কিছুর জন্য নির্ধারিত হয় IPoint

আমি প্রাথমিকভাবে নিম্নলিখিত প্রোগ্রামটির আউটপুট 2, 3 হবে বলে আশাবাদী, তবে এটি 0, 0।

interface IPoint {
    public int NumDims { get; } 
}

public struct Point2 : IPoint {
    public int NumDims => 2;
}

public struct Point3 : IPoint {
    public int NumDims => 3;
}

class Program
{
    static int GetDim<T>(T point) where T: IPoint => 0;
    static int GetDim(Point2 point) => point.NumDims;
    static int GetDim(Point3 point) => point.NumDims;

    static int GenericAlgorithm<T>(T point) where T : IPoint => GetDim(point);

    static void Main(string[] args)
    {
        Point2 p2;
        Point3 p3;
        int d1 = GenericAlgorithm(p2);
        int d2 = GenericAlgorithm(p3);
        Console.WriteLine("{0:d}", d1);        // returns 0 !!
        Console.WriteLine("{0:d}", d2);        // returns 0 !!
    }
}

ঠিক আছে, তাই কোনও কারণে কংক্রিটের ধরণের তথ্য হারিয়ে যায় GenericAlgorithm। কেন এটি ঘটে তা আমি পুরোপুরি বুঝতে পারি না তবে ঠিক আছে। আমি যদি এইভাবে এটি না করতে পারি তবে আমার কাছে অন্য বিকল্পগুলি কী আছে?


2
"ফ্যাল-ব্যাক ফাংশনও রয়েছে" এর উদ্দেশ্য কী, ঠিক কী? একটি ইন্টারফেস বাস্তবায়নের পুরো বিষয়টি হ'ল NumDimsসম্পত্তিটি উপলব্ধ guarantee আপনি কিছু ক্ষেত্রে এটিকে কেন উপেক্ষা করছেন?
জন উ

সুতরাং এটি সংকলন, মূলত। প্রাথমিকভাবে আমি ভেবেছিলাম যে রান-টাইমে জেআইটি সংকলক বিশেষায়িত বাস্তবায়ন না পেয়ে GetDim(যেমন আমি পাস করি Point4তবে GetDim<Point4>বিদ্যমান নেই) এর জন্য ফ্যাল ব্যাক ফাংশন প্রয়োজন । যাইহোক, সংকলকটি বিশেষায়িত বাস্তবায়ন সন্ধান করতে বিরক্ত করে বলে মনে হয় না।
মোহাম্মদমৌসা

1
@ ওয়াগি: আপনি বলেছেন যে "সংকলক বিশেষায়িত প্রয়োগের সন্ধান করতে বিরূপ লাগে না" যেন মনে হয় এটি ডিজাইনার এবং প্রয়োগকারীদের পক্ষ থেকে অলসতার বিষয়। এটা না। নেট থেকে জেনারিকগুলি কীভাবে উপস্থাপিত হয় তা বিষয়। এটি কেবলমাত্র C ++ তে টেম্পলেট করার মতো বিশেষত্ব নয়। একটি জেনেরিক পদ্ধতি প্রতিটি ধরণের আর্গুমেন্টের জন্য আলাদাভাবে সংকলিত হয় না - এটি একবার সংকলিত হয়। এর অবশ্যই পক্ষে মতামত রয়েছে, তবে এটি "বিরক্তিকর" হওয়ার বিষয় নয়।
জন স্কিটি

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

@ ওয়াগি: এটি জেআইটি- কম্পাইলার, এটি সি # সংকলক থেকে সম্পূর্ণ পৃথক বিষয় - এবং এটি সি # সংকলক যা ওভারলোড রেজোলিউশন করে। জেনেরিক পদ্ধতির আইএল কেবল একবার তৈরি করা হয় - প্রতি বিশেষজ্ঞের জন্য একবার নয়।
জন স্কিটি

উত্তর:


10

এই পদ্ধতি:

static int GenericAlgorithm<T>(T point) where T : IPoint => GetDim(point);

... সবসময় ডাকবে GetDim<T>(T point)। ওভারলোড রেজোলিউশন সংকলন সময়ে সঞ্চালিত হয় , এবং সেই পর্যায়ে অন্য কোন প্রয়োগযোগ্য পদ্ধতি নেই।

আপনি যদি মৃত্যুদন্ড কার্যকর করার সময় ওভারলোড রেজোলিউশনটি কল করতে চান তবে আপনার ডায়নামিক টাইপিং ব্যবহার করা দরকার, যেমন

static int GenericAlgorithm<T>(T point) where T : IPoint => GetDim((dynamic) point);

তবে এটির জন্য উত্তরাধিকার ব্যবহার করা সাধারণত একটি ভাল ধারণা - আপনার উদাহরণস্বরূপ, সম্ভবত আপনি কেবল একক পদ্ধতিতে ফিরে আসতে পারেন point.NumDims। আমি আপনার আসল কোডটি ধরে নিয়েছি যে সমতুল্যটি কর্কশ হওয়ার জন্য কিছু কারণ রয়েছে, তবে আরও প্রসঙ্গ ছাড়া আমরা কীভাবে বিশেষায়নের জন্য উত্তরাধিকারটি ব্যবহার করতে পারি সে সম্পর্কে পরামর্শ দিতে পারি না। সেগুলি যদিও আপনার বিকল্পগুলি:

  • লক্ষ্য নির্বাহের সময় প্রকারের ভিত্তিতে বিশেষায়নের জন্য উত্তরাধিকার (পছন্দসই)
  • এক্সিকিউশন-টাইম ওভারলোড রেজোলিউশনের জন্য গতিশীল টাইপিং

আসল পরিস্থিতি আমার একটি AxisAlignedBoundingBox2এবং AxisAlignedBoundingBox3। আমার একটি Containsস্থিতিশীল পদ্ধতি রয়েছে যা বাক্সগুলির সংগ্রহে একটি Line2বা Line3(যা বাক্সগুলির ধরণের উপর নির্ভর করে) রয়েছে কিনা তা নির্ধারণ করতে ব্যবহৃত হয় । উভয় প্রকারের মধ্যে অ্যালগোরিদম যুক্তি হুবহু এক, মাত্রার সংখ্যা ভিন্ন ভিন্ন। এছাড়াও কল আছে Intersectঅভ্যন্তরীণভাবে যে প্রয়োজন সঠিক টাইপ বিশেষ করা হবে। আমি ভার্চুয়াল ফাংশন কল / ডায়নামিক এড়াতে চাই, এজন্যই আমি জেনারিকগুলি ব্যবহার করছি ... অবশ্যই আমি কোডটি অনুলিপি / আটকানো এবং এগিয়ে যেতে পারি।
২hamed

1
@ ওয়াগি: কেবল বিবরণ থেকে এটিকে কল্পনা করা বেশ কঠিন। যদি আপনি উত্তরাধিকার ব্যবহার করে এটি করার চেষ্টা করতে সহায়তা চান তবে আমি আপনাকে একটি ন্যূনতম তবে সম্পূর্ণ উদাহরণ দিয়ে একটি নতুন প্রশ্ন তৈরি করার পরামর্শ দিচ্ছি।
জন স্কিটি

ঠিক আছে, করব, আমি এই উত্তরটি আপাতত গ্রহণ করব কারণ মনে হয় আমি ভাল উদাহরণ সরবরাহ করি নি।
মোহাম্মদমূছা

6

সি # 8.0 এর হিসাবে আপনার জেনেরিক পদ্ধতির পরিবর্তে আপনার ইন্টারফেসের জন্য একটি ডিফল্ট বাস্তবায়ন সরবরাহ করতে সক্ষম হওয়া উচিত।

interface IPoint {
    int NumDims { get => 0; }
}

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

static int GetDim(IPoint point) => point.NumDims;

3

ভিজিটর প্যাটার্ন

dynamicব্যবহারের বিকল্প হিসাবে , আপনি নীচের মত একটি দর্শনার্থী প্যাটার্ন ব্যবহার করতে পারেন :

interface IPoint
{
    public int NumDims { get; }
    public int Accept(IVisitor visitor);
}

public struct Point2 : IPoint
{
    public int NumDims => 2;

    public int Accept(IVisitor visitor)
    {
        return visitor.Visit(this);
    }
}

public struct Point3 : IPoint
{
    public int NumDims => 3;

    public int Accept(IVisitor visitor)
    {
        return visitor.Visit(this);
    }
}

public class Visitor : IVisitor
{
    public int Visit(Point2 toVisit)
    {
        return toVisit.NumDims;
    }

    public int Visit(Point3 toVisit)
    {
        return toVisit.NumDims;
    }
}

public interface IVisitor<T>
{
    int Visit(T toVisit);
}

public interface IVisitor : IVisitor<Point2>, IVisitor<Point3> { }

class Program
{
    static int GetDim<T>(T point) where T : IPoint => 0;
    static int GetDim(Point2 point) => point.NumDims;
    static int GetDim(Point3 point) => point.NumDims;

    static int GenericAlgorithm<T>(T point) where T : IPoint => point.Accept(new Visitor());

    static void Main(string[] args)
    {
        Point2 p2;
        Point3 p3;
        int d1 = GenericAlgorithm(p2);
        int d2 = GenericAlgorithm(p3);
        Console.WriteLine("{0:d}", d1);        // returns 2
        Console.WriteLine("{0:d}", d2);        // returns 3
    }
}

1

আপনি ক্লাস এবং ইন্টারফেসে গেটডিম ফাংশনটি কেন সংজ্ঞায়িত করবেন না? আসলে, আপনাকে গেটডিম ফাংশনটি সংজ্ঞায়িত করার দরকার নেই, কেবল সম্পত্তি নুমডিম ব্যবহার করুন।

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