জেনেরিক পদ্ধতিতে একাধিক (OR) টাইপ সীমাবদ্ধতা


135

পড়া এই , আমি শিখেছি সম্ভব ছিল একটি পদ্ধতি এটি একটি জেনেরিক পদ্ধতি উপার্জন একাধিক ধরনের পরামিতি গ্রহণ করতে অনুমতি দেয়। উদাহরণস্বরূপ, "ইউ" এটির একটি তা নিশ্চিত করতে নিম্নলিখিত কোডটি একধরণের বাধা দিয়ে ব্যবহৃত হয় IEnumerable<T>

public T DoSomething<U, T>(U arg) where U : IEnumerable<T>
{
    return arg.First();
}

আমি আরও কিছু কোড পেয়েছি যা একাধিক ধরণের সীমাবদ্ধতা যুক্ত করার অনুমতি দিয়েছে, যেমন:

public void test<T>(string a, T arg) where T: ParentClass, ChildClass 
{
    //do something
}

যাইহোক, এই কোডটি প্রয়োগ করে বলে মনে হচ্ছে argএটি উভয় প্রকারের ParentClass এবং উভয়ই হতে হবে ChildClass। আমি যা করতে চাই তা হ'ল আর্গ এক ধরণের ParentClass বা ChildClass নিম্নলিখিত পদ্ধতিতে হতে পারে :

public void test<T>(string a, T arg) where T: string OR Exception
{
//do something
}

আপনার সাহায্য সর্বদা হিসাবে প্রশংসা করা হয়!


4
আপনি কীভাবে কার্যকরভাবে এই জাতীয় পদ্ধতির দেহের অভ্যন্তরে জেনেরিক পদ্ধতিতে কাজ করতে পারেন (যদি না একাধিক প্রকারের সমস্ত নির্দিষ্ট বেস শ্রেণি থেকে প্রাপ্ত হয়, তবে এক্ষেত্রে কেন এটিকে টাইপ সীমাবদ্ধতা হিসাবে ঘোষণা করবেন না)?
ড্যামিয়েন_এ_বিশ্বাসীরা

@ দমিয়েন_সে_ অবিশ্বাসীরা নিশ্চিত না যে আপনি শরীরে কী বোঝাতে চাইছেন? আপনি যদি কোনওরকমভাবে অনুমতি দেওয়ার এবং শরীরে ম্যানুয়ালি পরীক্ষা করার অনুমতি না চান ... এবং আসল কোডে আমি লিখতে চাই (শেষ কোড স্নিপেট), আমি একটি স্ট্রিং বা ব্যতিক্রম পাস করতে সক্ষম হতে চাই, সুতরাং কোনও শ্রেণি নেই সেখানে সম্পর্ক (system.object ব্যতীত আমি কল্পনাও করি)
ম্যানসফিল্ড

1
এছাড়াও মনে রাখবেন লিখিতভাবে কোন ব্যবহার নেই যে where T : string, যেমন stringএকটি হল সিল বর্গ। কেবলমাত্র দরকারী জিনিস যা আপনি করতে পারেন তা হ'ল ওভারলোডগুলি সংজ্ঞায়িত করা stringএবং T : Exceptionনীচে তার উত্তরটিতে @ বটজ ৩০০০ ব্যাখ্যা করেছেন।
ম্যাটিয়াস বুয়েলেন্স 31:51

তবে যখন কোনও সম্পর্ক নেই, কেবলমাত্র যে পদ্ধতিগুলিতে আপনি কল করতে পারেন তা হ'ল argসংজ্ঞায়িতগুলি object- তবে কেন কেবল ছবি থেকে জেনেরিকগুলি সরিয়ে নাও এবং কীভাবে তৈরি করা যায় arg object? কি লাভ?
ড্যামিয়েন_এ_ অবিশ্বাস্য

1
@ মানসফিল্ড আপনি একটি ব্যক্তিগত পদ্ধতি তৈরি করতে পারেন যা কোনও অবজেক্টের প্যারামিটার গ্রহণ করে। উভয় ওভারলোড যে এক কল হবে। এখানে কোন জেনেরিকের প্রয়োজন নেই।
Botz3000

উত্তর:


68

সেটা সম্ভব না. আপনি তবে নির্দিষ্ট ধরণের জন্য ওভারলোডগুলি সংজ্ঞায়িত করতে পারেন:

public void test(string a, string arg);
public void test(string a, Exception arg);

সেগুলি যদি জেনেরিক শ্রেণীর অংশ হয় তবে এগুলি পদ্ধতির জেনেরিক সংস্করণের চেয়ে বেশি পছন্দ করা হবে।


1
মজাদার. এটি আমার কাছে ঘটেছিল তবে আমি ভেবেছিলাম এটি কোনও ফাংশনটি ব্যবহারের জন্য কোড ক্লিনার তৈরি করতে পারে। আহ ভাল, অনেক ধন্যবাদ! কৌতূহলের বাইরে, আপনি কি জানেন যে কোনও নির্দিষ্ট কারণ এটি সম্ভব নয় কি না? (এটি কি ইচ্ছাকৃতভাবে ভাষা থেকে বাদ দেওয়া হয়েছে?)
ম্যানসফিল্ড

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

3
@ ম্যানসফিল্ড, কারণ এটি একটি orসম্পর্ক জিনিসকে সাধারণের থেকে দূরের জিনিসগুলিকে দরকারী করে তোলে। আপনি চাই আছে কি করতে এবং যা জিনিসটা প্রতিফলন না। (Yuck!)।
ক্রিস পিফহল

29

বটজ উত্তর 100% সঠিক, এখানে একটি সংক্ষিপ্ত ব্যাখ্যা দেওয়া হয়েছে:

আপনি যখন কোনও পদ্ধতি লিখছেন (জেনেরিক বা না) এবং পদ্ধতিটি যে পরামিতিগুলি গ্রহণ করে সেগুলির ধরণের বিবরণ যখন আপনি একটি চুক্তি সংজ্ঞায়িত করছেন:

আপনি যদি আমাকে এমন কোনও জিনিস দেন যা টাইপ টি জানেন যে কীভাবে কীভাবে করতে হয় সেগুলি কীভাবে করতে হয় আমি কীভাবে 'এ' সরবরাহ করতে পারি: আমি যে ধরণের ঘোষণা করি তার ফিরতি মান, বা 'বি': এমন কিছু আচরণ যা ব্যবহার করে এই ধরণের।

যদি আপনি একবারে একাধিক প্রকারের চেষ্টা করে থাকেন (একটি বা থাকার সাথে) বা এটির সাথে এমন কোনও মান প্রত্যাবর্তনের চেষ্টা করে যা চুক্তিটি অস্পষ্ট হয়ে যায়:

আপনি যদি আমাকে এমন কোনও জিনিস দেন যা দড়িটি কীভাবে ঝাঁপিয়ে পড়তে জানে বা পাইকে 15 তম অঙ্কে কীভাবে গণনা করতে হয় তা আমি জানি তবে আমি এমন কোনও জিনিস ফিরিয়ে দেব যা মাছ ধরতে পারে বা কংক্রিটের সাথে মিশ্রিত করতে পারে।

সমস্যাটি হ'ল আপনি যখন পদ্ধতিটিতে প্রবেশ করেন তখন কোনও ধারণা নেই যে তারা আপনাকে একটি IJumpRopeবা একটি দিয়েছে PiFactory। তদ্ব্যতীত, আপনি যখন এগিয়ে যান এবং পদ্ধতিটি (ধরে নিলেন যে আপনি এটি যাদুবিদ্যামূলকভাবে সংকলন করতে পেরেছেন) ব্যবহার করবেন তখন আপনি সত্যই নিশ্চিত নন যে আপনার একটি Fisherবা একটি আছে কিনা AbstractConcreteMixer। মূলত এটি পুরো জিনিসটিকে আরও বিভ্রান্ত করে তোলে।

আপনার সমস্যার সমাধান দুটি সম্ভাবনার মধ্যে একটি:

  1. একাধিক পদ্ধতির সংজ্ঞা দিন যা প্রতিটি সম্ভাব্য রূপান্তর, আচরণ বা যা কিছু নির্ধারণ করে। এটাই বটজের উত্তর। প্রোগ্রামিং জগতে এটিকে ওভারলোডিং পদ্ধতি হিসাবে উল্লেখ করা হয়।

  2. একটি বেস ক্লাস বা ইন্টারফেস সংজ্ঞায়িত করুন যা জানেন যে পদ্ধতিটির জন্য আপনার প্রয়োজনীয় সমস্ত জিনিস কীভাবে করতে হবে এবং একটি পদ্ধতি রয়েছে কেবল সেই ধরণের take এটি বাস্তবায়নের ক্ষেত্রে কীভাবে তাদের ম্যাপিংয়ের পরিকল্পনা করে তা নির্ধারণ করতে একটি stringএবং Exceptionএকটি ছোট শ্রেণিতে জড়িত থাকতে পারে তবে তারপরে সবকিছু খুব পরিষ্কার এবং সহজেই পড়তে পারে। আমি এখন থেকে চার বছর পরে এসেছি এবং আপনার কোডটি পড়তে পারি এবং সহজেই বুঝতে পারি যে কী চলছে।

আপনি যেটি চয়ন করেন তা নির্ভর করে যে 1 এবং 2 কীভাবে জটিল পছন্দ হবে এবং এটি কতটা প্রসারিত হওয়া দরকার on

সুতরাং আপনার নির্দিষ্ট পরিস্থিতির জন্য আমি কল্পনা করতে যাচ্ছি আপনি কেবল ব্যতিক্রম থেকে কোনও বার্তা বা কিছু বের করছেন:

public interface IHasMessage
{
    string GetMessage();
}

public void test(string a, IHasMessage arg)
{
    //Use message
}

এখন আপনার যা দরকার তা হ'ল এমন একটি পদ্ধতি যা একটি stringএবং Exceptionএকটি আইএইচসমেসেজে রূপান্তরিত করে । খুব সহজ.


দুঃখিত @ Botz3000, সবেমাত্র আমি আপনার নামটি ভুল বানান লক্ষ্য করেছি।
ক্রিস পিফহল

অথবা সংকলকটি এই ফাংশনের মধ্যে ইউনিয়নের ধরণ হিসাবে ধরণের হুমকির সম্মুখীন হতে পারে এবং তার মধ্যে ফিরে আসার মানটি একই ধরণের হয় Type টাইপস্ক্রিপ্ট এটি করে।
অ্যালেক্স

@ অ্যালেক্স কিন্তু সি # এটি করে না।
ক্রিস Pfohl

এটা সত্য, কিন্তু এটা পারে। আমি এই উত্তরটি এমনভাবে পড়লাম যে এটি সক্ষম হবে না, আমি কি ভুল ব্যাখ্যা দিয়েছিলাম?
অ্যালেক্স

1
কথাটি হ'ল সি # জেনেরিক প্যারামিটার সীমাবদ্ধতা এবং জেনেরিকরা নিজেরাই সি ++ টেম্পলেটগুলির তুলনায় বেশ আদিম। সি # এর জন্য জেনেরিক ধরণের ক্ষেত্রে কী কী অপারেশন অনুমোদিত তা আগে থেকেই সংকলকটি আপনাকে জানান requires সেই তথ্য সরবরাহ করার উপায়টি হল একটি প্রয়োগের ইন্টারফেস সীমাবদ্ধকরণ (যেখানে টি: আইডিস্পোজেবল)। তবে আপনি জেনেরিক পদ্ধতিটি ব্যবহার করার জন্য আপনার টাইপটি কিছু ইন্টারফেস প্রয়োগ করতে চান না বা আপনার জেনেরিক কোডে এমন কিছু প্রকারের মঞ্জুরি দিতে চাইতে পারেন যা সাধারণ ইন্টারফেস রাখে না। যাত্রা। যে কোনও স্ট্রাক বা স্ট্রিংকে মঞ্জুর করুন যাতে মান ভিত্তিক তুলনার জন্য আপনি কেবল সমান (v1, v2) কল করতে পারেন।
ভখতং

8

চাইল্ডক্লাসের অর্থ যদি এটি প্যারেন্টক্লাস থেকে উদ্ভূত হয় তবে আপনি প্যারেন্টক্লাস এবং চাইল্ডক্লাস উভয়ই মেনে নিতে নিম্নলিখিতটি লিখতে পারেন;

public void test<T>(string a, T arg) where T: ParentClass 
{
    //do something
}

অন্যদিকে, আপনি যদি উভয়ের মধ্যে কোনও উত্তরাধিকারের সম্পর্ক না রেখে দুটি ভিন্ন ধরণের ব্যবহার করতে চান তবে আপনার একই ইন্টারফেসটি প্রয়োগকারী প্রকারগুলি বিবেচনা করা উচিত;

public interface ICommonInterface
{
    string SomeCommonProperty { get; set; }
}

public class AA : ICommonInterface
{
    public string SomeCommonProperty
    {
        get;set;
    }
}

public class BB : ICommonInterface
{
    public string SomeCommonProperty
    {
        get;
        set;
    }
}

তারপরে আপনি আপনার জেনেরিক ফাংশন হিসাবে লিখতে পারেন;

public void Test<T>(string a, T arg) where T : ICommonInterface
{
    //do something
}

ভাল ধারণা, বাদে আমি ভাবি না যে আমি উপরের মতামত অনুসারে একটি সিলড ক্লাস যা স্ট্রিংটি ব্যবহার করতে চাই আমি তা করতে সক্ষম হব ...
ম্যানসফিল্ড

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

আমি যা করছি, বাস্তবে, একটি সাধারণ ত্রুটি লগিং ফাংশন লিখছি। আমি সেই শেষ প্যারামিটারটি ত্রুটি সম্পর্কে তথ্যের একটি স্ট্রিং বা একটি ব্যতিক্রম হতে চাই, তবে আমি e.message + e.stacktrace কে যাইহোক স্ট্রিং হিসাবে সংরক্ষণ করি।
ম্যানসফিল্ড

আপনি সফলভাবে একটি নতুন ক্লাস লিখতে পারেন, বৈশিষ্ট্য হিসাবে বার্তা এবং ব্যতিক্রম সংরক্ষণ করুন। তারপরে আপনি জারিযোগ্য সত্য কিনা তা যাচাই করতে পারেন এবং বাকীটি করতে পারেন।
ডায়রিয়াল

1

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

using System;
using System.Diagnostics;

namespace Union {
    [DebuggerDisplay("{currType}: {ToString()}")]
    public struct Either<TP, TA> {
        enum CurrType {
            Neither = 0,
            Primary,
            Alternate,
        }
        private readonly CurrType currType;
        private readonly TP primary;
        private readonly TA alternate;

        public bool IsNeither => currType == CurrType.Primary;
        public bool IsPrimary => currType == CurrType.Primary;
        public bool IsAlternate => currType == CurrType.Alternate;

        public static implicit operator Either<TP, TA>(TP val) => new Either<TP, TA>(val);

        public static implicit operator Either<TP, TA>(TA val) => new Either<TP, TA>(val);

        public static implicit operator TP(Either<TP, TA> @this) => @this.Primary;

        public static implicit operator TA(Either<TP, TA> @this) => @this.Alternate;

        public override string ToString() {
            string description = IsNeither ? "" :
                $": {(IsPrimary ? typeof(TP).Name : typeof(TA).Name)}";
            return $"{currType.ToString("")}{description}";
        }

        public Either(TP val) {
            currType = CurrType.Primary;
            primary = val;
            alternate = default(TA);
        }

        public Either(TA val) {
            currType = CurrType.Alternate;
            alternate = val;
            primary = default(TP);
        }

        public TP Primary {
            get {
                Validate(CurrType.Primary);
                return primary;
            }
        }

        public TA Alternate {
            get {
                Validate(CurrType.Alternate);
                return alternate;
            }
        }

        private void Validate(CurrType desiredType) {
            if (desiredType != currType) {
                throw new InvalidOperationException($"Attempting to get {desiredType} when {currType} is set");
            }
        }
    }
}

উপরে বর্গ একটি টাইপ যে হতে পারে প্রতিনিধিত্ব করে পারেন টিপি বা টি এ। আপনি এটি যেমন ব্যবহার করতে পারেন (প্রকারগুলি আমার মূল উত্তরের দিকে ফিরে আসে):

// ...
public static Either<FishingBot, ConcreteMixer> DemoFunc(Either<JumpRope, PiCalculator> arg) {
  if (arg.IsPrimary) {
    return new FishingBot(arg.Primary);
  }
  return new ConcreteMixer(arg.Secondary);
}

// elsewhere:

var fishBotOrConcreteMixer = DemoFunc(new JumpRope());
var fishBotOrConcreteMixer = DemoFunc(new PiCalculator());

গুরুত্বপূর্ণ নোট:

  • আপনি যদি IsPrimaryপ্রথমে পরীক্ষা না করেন তবে রানটাইম ত্রুটি পাবেন ।
  • আপনি যে কোনও IsNeither IsPrimaryবা যাচাই করতে পারেন IsAlternate
  • আপনি Primaryএবং মাধ্যমে মান অ্যাক্সেস করতে পারেনAlternate
  • টিপি / টিএ এবং উভয়ের মধ্যে অন্তর্নিহিত রূপান্তরকারী রয়েছে আপনাকে মানগুলি বা Eitherযে কোনও জায়গায় প্রত্যাশিত হয় যেখানে পাস করতে দেয় । যদি আপনি এমন একটি পাস করেন যা Eitherএকটি TAবা TPপ্রত্যাশিত হয় তবে Eitherএটিতে ভুল ধরণের মান রয়েছে তবে আপনি রানটাইম ত্রুটি পাবেন।

আমি সাধারণত এটি ব্যবহার করি যেখানে কোনও ফলাফল বা ত্রুটি ফিরে আসার জন্য আমি একটি পদ্ধতি চাই। এটি সত্যিই সেই স্টাইলের কোডটি পরিষ্কার করে। আমি খুব মাঝেমধ্যে ( খুব কমই ) এটিকে পদ্ধতি ওভারলোডের প্রতিস্থাপন হিসাবে ব্যবহার করি। বাস্তবতাত্ত্বিকভাবে এটি এই ধরনের ওভারলোডের জন্য খুব দরিদ্র বিকল্প।

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