এমন কোনও প্রতিবন্ধকতা রয়েছে যা আমার জেনেরিক পদ্ধতিটি সংখ্যার ক্ষেত্রে সীমাবদ্ধ করে?


364

জেনেরিকের সাথে কোনও জেনেরিক ধরণের আর্গুমেন্টকে Tকেবল সীমাবদ্ধ করার উপায় আছে কি কেউ আমাকে বলতে পারে :

  • Int16
  • Int32
  • Int64
  • UInt16
  • UInt32
  • UInt64

আমি whereকীওয়ার্ড সম্পর্কে সচেতন , তবে কেবলমাত্র এই ধরণের জন্য একটি ইন্টারফেস পাই না ,

কিছুটা এইরকম:

static bool IntegerFunction<T>(T value) where T : INumeric 

উত্তর:


140

সি # এটি সমর্থন করে না। ব্রজ একেলের সাথে একটি সাক্ষাত্কারে এই বৈশিষ্ট্যটি বাস্তবায়িত না করার কারণগুলি হেজলসবার্গ বর্ণনা করেছেন :

এবং এটি স্পষ্ট নয় যে যুক্ত হওয়া জটিলতা আপনার যে সামান্য ফলনের জন্য মূল্যবান। আপনি যদি কিছু করতে চান তবে সীমাবদ্ধতা সিস্টেমে সরাসরি সমর্থন না করা থাকলে আপনি এটি কারখানার নিদর্শন দিয়ে করতে পারেন। Matrix<T>উদাহরণস্বরূপ আপনার একটি থাকতে পারে এবং এতে আপনি Matrixকোনও বিন্দু পণ্য পদ্ধতিটি সংজ্ঞায়িত করতে চান। যে কোর্স তার মানে কি শেষ পর্যন্ত বুঝতে সংখ্যাবৃদ্ধি দুই করতে হবে Tগুলি, কিন্তু আপনি যা বলতে না পারে একটি বাধ্যতা যেমন, অন্তত যদি না Tহয় int, doubleঅথবা float। তবে আপনি যা করতে পারেন তা হ'ল আপনার Matrixআর্গুমেন্ট হিসাবে গ্রহণ করা Calculator<T>, এবং এর মধ্যে Calculator<T>একটি পদ্ধতি বলে multiply। আপনি এটি বাস্তবায়ন করতে যান এবং আপনি এটি পাস Matrix

যাইহোক, এটি মোটামুটি সংশ্লেষিত কোডের দিকে পরিচালিত করে, যেখানে ব্যবহারকারীর Calculator<T>প্রতিটি Tব্যবহারের জন্য তাদের নিজস্ব বাস্তবায়ন সরবরাহ করতে হবে। যতক্ষণ না এটি এক্সটেনসিবল হতে হবে, যেমন আপনি যদি কেবলমাত্র নির্দিষ্ট সংখ্যক প্রকারের সমর্থন করতে চান যেমন intএবং এবং double, আপনি তুলনামূলক সহজ ইন্টারফেস দিয়ে দূরে যেতে পারেন:

var mat = new Matrix<int>(w, h);

( একটি গিটহাব গিস্টে ন্যূনতম বাস্তবায়ন ))

তবে আপনি যত তাড়াতাড়ি চাইবেন যে ব্যবহারকারী তাদের নিজস্ব, কাস্টম প্রকার সরবরাহ করতে সক্ষম হবেন, আপনাকে এই বাস্তবায়নটি খুলতে হবে যাতে ব্যবহারকারী তাদের নিজস্ব Calculatorদৃষ্টান্ত সরবরাহ করতে পারে । উদাহরণস্বরূপ, একটি ম্যাট্রিক্স ইনস্ট্যান্ট করতে যা একটি কাস্টম দশমিক ভাসমান পয়েন্ট বাস্তবায়ন DFPব্যবহার করে, আপনাকে এই কোডটি লিখতে হবে:

var mat = new Matrix<DFP>(DfpCalculator.Instance, w, h);

... এবং এর জন্য সকল সদস্যকে বাস্তবায়ন করুন DfpCalculator : ICalculator<DFP>

দুর্ভাগ্যক্রমে একই সীমাবদ্ধতা ভাগ করে নেওয়ার একটি বিকল্প হ'ল সের্গেই শান্দারের উত্তরে আলোচিত নীতি ক্লাসগুলির সাথে কাজ করা ।


25
বিটিডব্লিউ, মিসকিল একটি জেনেরিক ক্লাস সরবরাহ করে যা ঠিক এটি করে; Operator/ Operator<T>; yoda.arachsys.com/csharp/miscutil/usage/genericoperators.html
মার্ক গ্র্যাভেল

1
@ মার্ক: ভাল মন্তব্য। যাইহোক, কেবল স্পষ্ট করে বললে, আমি মনে করি না যে হেজলসবার্গ কোড তৈরির ক্ষেত্রে কোড জেনারেশনটিকে সমস্যার সমাধান হিসাবে উল্লেখ করছেন Operator<T>(যেহেতু সাক্ষাত্কারটি Expressionsকাঠামোর অস্তিত্বের অনেক আগে দেওয়া হয়েছিল , যদিও কেউ তা করতে পারে অবশ্যই ব্যবহার Reflection.Emit) - এবং আমি হতে চাই সত্যিই আগ্রহী তার কার্যসংক্রান্ত।
কনরাড রুডলফ

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

14
হাইজবার্গের এই বাক্যটির সাথে আমি একমত নই "" সুতরাং এক অর্থে সি ++ টেম্পলেটগুলি আসলে টাইপযুক্ত, বা আলগাভাবে টাইপ করা হয়। যেখানে সি # জেনেরিকগুলি দৃ strongly়ভাবে টাইপ করা হয়। " এটি সত্যিই বিপণন বিএস সি # প্রচার করতে। স্ট্রং / দুর্বল-টাইপিংয়ের সাথে ডায়াগনস্টিকসের গুণমান নেই। অন্যথায়: আকর্ষণীয় সন্ধান করুন।
সেবাস্তিয়ান মাচ

100

এই প্রশ্নের জনপ্রিয়তা এবং এই জাতীয় ফাংশনের পিছনে আগ্রহ বিবেচনা করে আমি অবাক হয়ে দেখছি যে টি 4 এর সাথে জড়িত কোনও উত্তর এখনও নেই।

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

হুপসের মধ্য দিয়ে যাওয়া এবং সংকলন-সময় নিশ্চিততার ত্যাগের পরিবর্তে আপনি কেবল আপনার পছন্দ মতো প্রতিটি ফাংশন তৈরি করতে পারেন এবং সেই অনুযায়ী ব্যবহার করতে পারেন (সংকলনের সময়!)।

এই কাজ করার জন্য:

  • GenericNumberMethodTemplate.tt নামে একটি নতুন পাঠ্য টেম্পলেট ফাইল তৈরি করুন ।
  • স্বয়ংক্রিয়ভাবে উত্পন্ন কোডটি সরান (আপনি এর বেশিরভাগ অংশ রাখবেন তবে কিছুটির প্রয়োজন নেই)।
  • নিম্নলিখিত স্নিপেট যোগ করুন:
<#@ template language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Core" #>

<# Type[] types = new[] {
    typeof(Int16), typeof(Int32), typeof(Int64),
    typeof(UInt16), typeof(UInt32), typeof(UInt64)
    };
#>

using System;
public static class MaxMath {
    <# foreach (var type in types) { 
    #>
        public static <#= type.Name #> Max (<#= type.Name #> val1, <#= type.Name #> val2) {
            return val1 > val2 ? val1 : val2;
        }
    <#
    } #>
}

এটাই. আপনি এখন সম্পন্ন হয়েছে।

এই ফাইলটি সংরক্ষণ করা স্বয়ংক্রিয়ভাবে এটিকে উত্স ফাইলে সংকলন করবে:

using System;
public static class MaxMath {
    public static Int16 Max (Int16 val1, Int16 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static Int32 Max (Int32 val1, Int32 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static Int64 Max (Int64 val1, Int64 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static UInt16 Max (UInt16 val1, UInt16 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static UInt32 Max (UInt32 val1, UInt32 val2) {
        return val1 > val2 ? val1 : val2;
    }
    public static UInt64 Max (UInt64 val1, UInt64 val2) {
        return val1 > val2 ? val1 : val2;
    }
}

আপনার mainপদ্ধতিতে আপনি যাচাই করতে পারেন যে আপনার সংকলন-সময় নিশ্চিততা রয়েছে:

namespace TTTTTest
{
    class Program
    {
        static void Main(string[] args)
        {
            long val1 = 5L;
            long val2 = 10L;
            Console.WriteLine(MaxMath.Max(val1, val2));
            Console.Read();
        }
    }
}

এখানে চিত্র বর্ণনা লিখুন

আমি একটি মন্তব্যে এগিয়ে যাব: না, এটি ডিআরওয়াই নীতি লঙ্ঘন নয়। DRY নীতিটি এমন একাধিক স্থানে নকল কোড থেকে লোকদের রোধ করার জন্য রয়েছে যা অ্যাপ্লিকেশনটি বজায় রাখা শক্ত হয়ে উঠবে।

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

এটি আপনার নিজস্ব কাস্টম সংজ্ঞা সহ ব্যবহার করার জন্য, আপনার উত্পন্ন কোডে একটি নেমস্পেসের ঘোষণা (নিশ্চিত করুন যে এটি আপনার নিজের প্রয়োগকরণের সংজ্ঞা দিবেন ঠিক সেইরূপ)) এবং শ্রেণিটি চিহ্নিত করুন partial। এরপরে, আপনার টেম্পলেট ফাইলটিতে এই লাইনগুলি যুক্ত করুন যাতে এটি চূড়ান্ত সংকলনে অন্তর্ভুক্ত হবে:

<#@ import namespace="TheNameSpaceYouWillUse" #>
<#@ assembly name="$(TargetPath)" #>

আসুন সত্য কথা: এটি দুর্দান্ত।

অস্বীকৃতি: এই নমুনা কেভিন হ্যাজার্ড এবং জেসন বক, ম্যানেজিং পাবলিকেশনস দ্বারানেট মধ্যে মেটাপোগ্র্যামিং দ্বারা প্রবলভাবে প্রভাবিত হয়েছে ।


এটি বেশ দুর্দান্ত, তবে কি পদ্ধতিগুলি বিভিন্ন জেনেরিক ধরণের Tযা বিভিন্ন IntXশ্রেণীর থেকে উত্তরাধিকারসূত্রে গ্রহণ করে তা গ্রহণ করার জন্য এই সমাধানটি সংশোধন করা সম্ভব হবে ? আমি এই সমাধানটি পছন্দ করি কারণ এটি সময় সাশ্রয় করে, তবে এটির জন্য এটি 100% সমাধান করে (যতটা সুন্দর না হওয়া সত্ত্বেও সি # এই ধরণের প্রতিবন্ধকতার পক্ষে সমর্থন করেছিল, অন্তর্নির্মিত) প্রতিটি উত্পন্ন পদ্ধতি এখনও জেনেরিক হওয়া উচিত তারা IntXXক্লাসগুলির মধ্যে একটির কাছ থেকে উত্তরাধিকারসূত্রে প্রাপ্ত এমন ধরণের কোনও অবজেক্ট ফেরত দিতে পারে ।
জ্যাকারি নাইবল

1
@ জাচারিনিবেল: IntXXপ্রকারগুলি হ'ল স্ট্রাক্ট যার অর্থ তারা প্রথম স্থানে উত্তরাধিকার সমর্থন করে না । এমনকি যদি তা হয়ে থাকে তবে লিসকোভের প্রতিস্থাপনের নীতিটি (যা আপনি সলড আইডিয়াম থেকে জানতে পারেন) প্রয়োগ করে: যদি পদ্ধতিটি সংজ্ঞায়িত হয় Xএবং সংজ্ঞা অনুসারে যদি কোনও Yশিশু হয় Xতবে তার Yবিকল্প হিসাবে সেই পদ্ধতিতে যে কোনওটিকে পাস করতে সক্ষম হওয়া উচিত এর বেস টাইপ।
জেরোইন ভেনেভেল

1
নীতিমালা stackoverflow.com/questions/32664/… ব্যবহার করে এই কর্মীরা ক্লাস উত্পন্ন করতে T4 ব্যবহার করে না
সের্গেই শানদার

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

1
খুব শীতল এবং আমি এটি ব্যবহার শুরু করতেই শুরু করেছিলাম তখন আমি মনে করেছি রিফ্যাক্টরিংয়ের জন্য আমি রেশার্পারের উপর কতটা নির্ভরশীল এবং আপনি টি 4 টেমপ্লেটের মাধ্যমে রিফেক্টরটির নাম পরিবর্তন করতে পারবেন না। এটি সমালোচনামূলক নয় তবে বিবেচনা করার মতো।
bradgonesurfing

86

এটির জন্য কোনও বাধা নেই। সংখ্যার গণনার জন্য জেনেরিকগুলি ব্যবহার করতে ইচ্ছুক সবার পক্ষে এটি একটি আসল সমস্যা।

আমি আরও এগিয়ে গিয়ে বলব যে আমাদের দরকার

static bool GenericFunction<T>(T value) 
    where T : operators( +, -, /, * )

অথবা এমনকি

static bool GenericFunction<T>(T value) 
    where T : Add, Subtract

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

আপনি কোডেপ্রজেক্টে এখানে অন্য কিছু (অনুরূপ INullable<T>) এর মতো নম্বর গুটিয়ে রাখতে পারেন


আপনি রানটাইমে (অপারেটরদের প্রতিফলিত করে বা প্রকারের জন্য পরীক্ষা করে) সীমাবদ্ধতা প্রয়োগ করতে পারেন তবে জেনেরিকটি প্রথম স্থানে রাখার সুবিধাটি হারাবে না।


2
আমি অবাক হয়েছি আপনি যদি জেনেরিক অপারেটরদের জন্য মিস্কটিলের সমর্থন দেখেছেন ... yoda.arachsys.com/csharp/miscutil/usage/genericoperators.html
মার্ক গ্র্যাভেল

10
হ্যাঁ - জন স্কিটি কিছুক্ষণ আগে তাদের দিকে আমার দিকে ইঙ্গিত করেছিল (তবে এই বছরের পুরানো প্রতিক্রিয়ার পরে) - তারা একটি চালাক ধারণা, তবে আমি এখনও সঠিক প্রতিবন্ধকতা সমর্থন চাই।
কিথ

1
অপেক্ষা করুন, where T : operators( +, -, /, * )আইনী সি #? নবাগত প্রশ্নের জন্য দুঃখিত।
kdbanman

@ কেডব্যানম্যান আমি এটি মনে করি না। কিথ বলছেন যে সি # ওপি যা জিজ্ঞাসা করছে তা সমর্থন করে না এবং পরামর্শ দিচ্ছে যে আমাদের করতে সক্ষম হওয়া উচিত where T : operators( +, -, /, * ), তবে পারে না।
এএমটার্প

62

নীতিগুলি ব্যবহার করে কার্যকরী:

interface INumericPolicy<T>
{
    T Zero();
    T Add(T a, T b);
    // add more functions here, such as multiplication etc.
}

struct NumericPolicies:
    INumericPolicy<int>,
    INumericPolicy<long>
    // add more INumericPolicy<> for different numeric types.
{
    int INumericPolicy<int>.Zero() { return 0; }
    long INumericPolicy<long>.Zero() { return 0; }
    int INumericPolicy<int>.Add(int a, int b) { return a + b; }
    long INumericPolicy<long>.Add(long a, long b) { return a + b; }
    // implement all functions from INumericPolicy<> interfaces.

    public static NumericPolicies Instance = new NumericPolicies();
}

আলগোরিদিম:

static class Algorithms
{
    public static T Sum<P, T>(this P p, params T[] a)
        where P: INumericPolicy<T>
    {
        var r = p.Zero();
        foreach(var i in a)
        {
            r = p.Add(r, i);
        }
        return r;
    }

}

ব্যবহার:

int i = NumericPolicies.Instance.Sum(1, 2, 3, 4, 5);
long l = NumericPolicies.Instance.Sum(1L, 2, 3, 4, 5);
NumericPolicies.Instance.Sum("www", "") // compile-time error.

সমাধান সংকলন-সময় নিরাপদ। সিটিলিজার্ড ফ্রেমওয়ার্ক । নেট 4.0 এর জন্য সংকলিত সংস্করণ সরবরাহ করে। ফাইলটি lib / নেট ফ্রেমওয়ার্ক 4.0 / সিটিলিজার্ড.পলিসি.ডিল।

এটি নুগেটেও উপলব্ধ: https://www.nuget.org/packages/CityLizard/সিটিলিজার্ড.পলিসি.আই কাঠামো দেখুন ।


জেনেরিক পরামিতিগুলির তুলনায় কম ফাংশন আর্গুমেন্ট থাকা অবস্থায় আমার এই প্যাটার্নটিতে সমস্যা ছিল। খোলা হয়েছে stackoverflow.com/questions/36048248/...
xvan

কোন কারণে ব্যবহার করছেন struct? আমি যদি পরিবর্তে সিঙ্গলটন-ক্লাস ব্যবহার করি এবং উদাহরণটি পরিবর্তন করি public static NumericPolicies Instance = new NumericPolicies();এবং তারপরে এই নির্মাণকারী যুক্ত করি private NumericPolicies() { }
এমকাজেম আখগারি

@ এমকাজেমআখগারি আপনি সিঙ্গলটন ব্যবহার করতে পারেন। আমি কাঠামো পছন্দ না। তত্ত্বগতভাবে, এটি সংকলক / সিএলআর দ্বারা অনুকূলিত করা যেতে পারে কারণ স্ট্রাক্টটিতে কোনও তথ্য নেই। সিঙ্গেলনের ক্ষেত্রে, আপনি এখনও একটি রেফারেন্স পাস করবেন, এটি জিসির উপর অতিরিক্ত চাপ যুক্ত করতে পারে। আরেকটি সুবিধা হ'ল স্ট্রাক্ট নাল :-) হতে পারে না।
সের্গেই শানদার 21

আমি বলছিলাম যে আপনি একটি খুব স্মার্ট সমাধান পেয়েছেন, তবে সমাধানটি আমার পক্ষে খুব সীমাবদ্ধ: আমি এটি ব্যবহার করতে যাচ্ছিলাম T Add<T> (T t1, T t2), তবে Sum()কেবল তখনই কাজ করে যখন এটি পরামিতিগুলি থেকে নিজের ধরণের টি পুনরুদ্ধার করতে পারে, যা সম্ভব নয় which যখন এটি অন্য জেনেরিক ফাংশনে এম্বেড থাকে।
টোবিয়াস কানৌস

16

এই প্রশ্নটি একটি FAQ এর কিছুটা, সুতরাং আমি এটি উইকি হিসাবে পোস্ট করছি (যেহেতু আমি এর আগে পোস্ট করেছি তবে এটি একটি পুরানো); যাহাই হউক না কেন ...

আপনি নেট। এর কোন সংস্করণ ব্যবহার করছেন? আপনি যদি .NET 3.5 ব্যবহার করে থাকেন তবে আমার কাছে মিসিকিল (ফ্রি ইত্যাদি) জেনেরিক অপারেটরগুলি প্রয়োগ রয়েছে ।

T Add<T>(T x, T y)এটিতে বিভিন্ন ধরণের (মত DateTime + TimeSpan) গাণিতিকগুলির মতো পদ্ধতি এবং অন্যান্য রূপ রয়েছে ।

তদ্ব্যতীত, এটি সমস্ত অন্তর্নির্মিত, উত্তোলন এবং bespoke অপারেটরদের জন্য কাজ করে এবং প্রতিনিধিদের সম্পাদনা করে।

এটি কেন জটিল তা নিয়ে কিছু অতিরিক্ত পটভূমি এখানে

আপনি এটিও জানতে চাইতে পারেন যে dynamic(4.0) বাছাইয়ের মাধ্যমেও এই সমস্যাটি পরোক্ষভাবে সমাধান হয় - যেমন

dynamic x = ..., y = ...
dynamic result = x + y; // does what you expect

14

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

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

static bool IntegerFunction<T>(T value) where T : struct {
  if (typeof(T) != typeof(Int16)  &&
      typeof(T) != typeof(Int32)  &&
      typeof(T) != typeof(Int64)  &&
      typeof(T) != typeof(UInt16) &&
      typeof(T) != typeof(UInt32) &&
      typeof(T) != typeof(UInt64)) {
    throw new ArgumentException(
      string.Format("Type '{0}' is not valid.", typeof(T).ToString()));
  }

  // Rest of code...
}

যা আমি জানি একটু কুৎসিত, তবে কমপক্ষে প্রয়োজনীয় সীমাবদ্ধতা সরবরাহ করে।

আমি এই বাস্তবায়নের জন্য সম্ভাব্য পারফরম্যান্সের প্রভাবগুলিও সন্ধান করব, সম্ভবত খুব দ্রুত একটি উপায় আছে।


13
+1, তবে, // Rest of code...এটি সীমাবদ্ধতা দ্বারা সংজ্ঞায়িত অপারেশনগুলির উপর নির্ভর করে যদি সংকলন নাও করতে পারে।
নিক

1
রূপান্তর করুন। টুআইএনটিএক্সএক্স (মান) "// বাকী কোড" সংকলন করতে সহায়তা করতে পারে - কমপক্ষে অবধি রিটার্ন টাইপ ইন্টিজার ফাংশন টিও টাইপ টি না হয়, তারপরে আপনি হুপড হন। :-p
Yoyo

-1; @ নিক দ্বারা প্রদত্ত কারণে এটি কাজ করে না। যে মুহুর্তে আপনি কোনও গাণিতিক ক্রিয়াকলাপগুলি // Rest of code...পছন্দ করার মতো value + valueবা করার চেষ্টা করছেন value * value, আপনি একটি সংকলন ত্রুটি পেয়েছেন।
মার্ক

13

সম্ভবত আপনি সবচেয়ে কাছের এটি করতে পারেন

static bool IntegerFunction<T>(T value) where T: struct

আপনি নিম্নলিখিতটি করতে পারতেন কিনা তা নিশ্চিত নন

static bool IntegerFunction<T>(T value) where T: struct, IComparable
, IFormattable, IConvertible, IComparable<T>, IEquatable<T>

এত নির্দিষ্ট কোনও কিছুর জন্য, প্রতিটি প্রকারের জন্য কেবল অতিরিক্ত চাপ কেন নয়, তালিকাটি এত ছোট এবং এতে সম্ভবত মেমরির পদক্ষেপ কম হবে।


6

সি # 7.3 সঙ্গে প্রারম্ভকালীন, আপনি কাছাকাছি ব্যবহার করতে পারেন পড়তা - অপরিচালিত বাধ্যতা নির্দিষ্ট করার যে একটি টাইপ প্যারামিটার একটি অ-পয়েন্টার, অ-nullable হয় অপরিচালিত প্রকার।

class SomeGeneric<T> where T : unmanaged
{
//...
}

নিয়ন্ত্রণহীন বাধা কাঠামো বাধা বোঝায় এবং কাঠামো বা নতুন () বাধাগুলির সাথে একত্রিত হতে পারে না।

কোনও ধরণ হ'ল পরিচালনাহীন টাইপ হয় যদি এটি নিম্নলিখিত ধরণের কোনও হয়:

  • এসবিটি, বাইট, সংক্ষিপ্ত, ushort, int, uint, দীর্ঘ, উলং, চর, ভাসা, ডাবল, দশমিক, বা বুল
  • যে কোনও এনাম টাইপ
  • যে কোনও পয়েন্টার প্রকার
  • যে কোনও ব্যবহারকারীর দ্বারা সংজ্ঞায়িত স্ট্রাক প্রকারের কেবল পরিচালনা ব্যবস্থাবিহীন প্রকারের ক্ষেত্রগুলি রয়েছে এবং সি # 7.3 এবং তার আগের ক্ষেত্রে, এটি কোনও নির্মাণকৃত ধরণের নয় (এমন কোনও ধরণের অন্তত একটি প্রকারের যুক্তি অন্তর্ভুক্ত)

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

    class SomeGeneric<T> where T : unmanaged, IComparable, IEquatable<T>
    {
    //...
    }

চমৎকার, তবে যথেষ্ট নয় ... উদাহরণস্বরূপ, সীমাবদ্ধতার মধ্যে DateTimeপড়ে unmanaged, IComparable, IEquatable<T>..
অ্যাডাম কালভেট বোহল

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

4

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

    class Something<TCell>
    {
        internal static TCell Sum(TCell first, TCell second)
        {
            if (typeof(TCell) == typeof(int))
                return (TCell)((object)(((int)((object)first)) + ((int)((object)second))));

            if (typeof(TCell) == typeof(double))
                return (TCell)((object)(((double)((object)first)) + ((double)((object)second))));

            return second;
        }
    }

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

        internal static int Sum(int first, int second)
        {
            return first + second;
        }

একটি অভিজ্ঞতা অভিজ্ঞতা সরবরাহ করার জন্য আপনাকে ধন্যবাদ!
zsf222

প্রতিটি ধরণের জন্য একই পদ্ধতি তৈরি করা কি এক নয়?
লুইস

3

এই সমস্যাগুলি সমাধান করার জন্য আমি একটি সামান্য গ্রন্থাগারের কার্যকারিতা তৈরি করেছি:

পরিবর্তে:

public T DifficultCalculation<T>(T a, T b)
{
    T result = a * b + a; // <== WILL NOT COMPILE!
    return result;
}
Console.WriteLine(DifficultCalculation(2, 3)); // Should result in 8.

আপনি লিখতে পারেন:

public T DifficultCalculation<T>(Number<T> a, Number<T> b)
{
    Number<T> result = a * b + a;
    return (T)result;
}
Console.WriteLine(DifficultCalculation(2, 3)); // Results in 8.

আপনি এখানে উত্স কোডটি পেতে পারেন: /codereview/26022/improvement-requmitted-for-generic-calculator- এবং- generic-number


2

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

আপনি যা চান তার সবগুলি যদি পূর্ণসংখ্যার হয় তবে জেনেরিক ব্যবহার করবেন না, এটি জেনেরিক নয়; বা আরও ভাল, অন্য কোনও প্রকারটি পরীক্ষা করে তা প্রত্যাখ্যান করুন।


2

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

স্ট্যাটিক বুল ইন্টিজার ফাংশন <টি> (টি মান) যেখানে টি: আইকনপমারেবল, আইফোর্মেটেবল, আইকনভারটেবল, আইকোম্যাপারেবল <টি>, আইকুয়েটেবল <টি>, স্ট্রাক্ট {...


2

আপনি যদি .NET 4.0 এবং তারপরে ব্যবহার করছেন তবে আপনি কেবল পদ্ধতি আর্গুমেন্ট হিসাবে ডায়নামিক ব্যবহার করতে পারেন এবং রানটাইম যাচাই করতে পারেন যে উত্তীর্ণ ডায়নামিক আর্গুমেন্ট প্রকারটি সংখ্যা / পূর্ণসংখ্যার প্রকার।

যদি পাস ধরণ গতিশীল হয় না সাংখ্যিক / পূর্ণসংখ্যা লিখে ব্যতিক্রম নিক্ষেপ করা।

একটি আদর্শ সংক্ষিপ্ত কোড যা ধারণাটি বাস্তবায়ন করে তা হ'ল:

using System;
public class InvalidArgumentException : Exception
{
    public InvalidArgumentException(string message) : base(message) {}
}
public class InvalidArgumentTypeException : InvalidArgumentException
{
    public InvalidArgumentTypeException(string message) : base(message) {}
}
public class ArgumentTypeNotIntegerException : InvalidArgumentTypeException
{
    public ArgumentTypeNotIntegerException(string message) : base(message) {}
}
public static class Program
{
    private static bool IntegerFunction(dynamic n)
    {
        if (n.GetType() != typeof(Int16) &&
            n.GetType() != typeof(Int32) &&
            n.GetType() != typeof(Int64) &&
            n.GetType() != typeof(UInt16) &&
            n.GetType() != typeof(UInt32) &&
            n.GetType() != typeof(UInt64))
            throw new ArgumentTypeNotIntegerException("argument type is not integer type");
        //code that implements IntegerFunction goes here
    }
    private static void Main()
    {
         Console.WriteLine("{0}",IntegerFunction(0)); //Compiles, no run time error and first line of output buffer is either "True" or "False" depends on the code that implements "Program.IntegerFunction" static method.
         Console.WriteLine("{0}",IntegerFunction("string")); //Also compiles but it is run time error and exception of type "ArgumentTypeNotIntegerException" is thrown here.
         Console.WriteLine("This is the last Console.WriteLine output"); //Never reached and executed due the run time error and the exception thrown on the second line of Program.Main static method.
    }

অবশ্যই এই সমাধানটি কেবল রান টাইমে কাজ করে তবে সংকলনের সময় কখনও নয়।

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

এটি বোঝা যায় যে মোড়ানো গতিশীল সর্বদা শ্রেণি / কাঠামোর ব্যক্তিগত সদস্য এবং এটি স্ট্রাক্ট / শ্রেণির একমাত্র সদস্য এবং স্ট্রাক্ট / শ্রেণির একমাত্র সদস্যের নাম "মান"।

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

এছাড়া ইন্দ্রিয় struct হয় / বর্গ আছে তোলে বিশেষ / অনন্য কন্সট্রাকটর যে গ্রহণ করে গতিশীল যুক্তি হল যে সূচনা এটি শুধুমাত্র ব্যক্তিগত গতিশীল "মান" বলা সদস্য কিন্তু যেমন পরিবর্তক এই কন্সট্রাকটর হয় ব্যক্তিগত অবশ্যই।

ক্লাস / স্ট্রাক্ট প্রস্তুত হয়ে গেলে আর্গুমেন্টের ধরণের পূর্ণসংখ্যার ধরণটি সংজ্ঞায়িত করা হয়েছে এমন শ্রেণি / কাঠামো হিসাবে সংজ্ঞায়িত করা হয়।

একটি আদর্শ দীর্ঘ কোড যা ধারণাটি বাস্তবায়ন করে তা হ'ল:

using System;
public struct Integer
{
    private dynamic value;
    private Integer(dynamic n) { this.value = n; }
    public Integer(Int16 n) { this.value = n; }
    public Integer(Int32 n) { this.value = n; }
    public Integer(Int64 n) { this.value = n; }
    public Integer(UInt16 n) { this.value = n; }
    public Integer(UInt32 n) { this.value = n; }
    public Integer(UInt64 n) { this.value = n; }
    public Integer(Integer n) { this.value = n.value; }
    public static implicit operator Int16(Integer n) { return n.value; }
    public static implicit operator Int32(Integer n) { return n.value; }
    public static implicit operator Int64(Integer n) { return n.value; }
    public static implicit operator UInt16(Integer n) { return n.value; }
    public static implicit operator UInt32(Integer n) { return n.value; }
    public static implicit operator UInt64(Integer n) { return n.value; }
    public static Integer operator +(Integer x, Int16 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, Int32 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, Int64 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, UInt16 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, UInt32 y) { return new Integer(x.value + y); }
    public static Integer operator +(Integer x, UInt64 y) { return new Integer(x.value + y); }
    public static Integer operator -(Integer x, Int16 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, Int32 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, Int64 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, UInt16 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, UInt32 y) { return new Integer(x.value - y); }
    public static Integer operator -(Integer x, UInt64 y) { return new Integer(x.value - y); }
    public static Integer operator *(Integer x, Int16 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, Int32 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, Int64 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, UInt16 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, UInt32 y) { return new Integer(x.value * y); }
    public static Integer operator *(Integer x, UInt64 y) { return new Integer(x.value * y); }
    public static Integer operator /(Integer x, Int16 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, Int32 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, Int64 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, UInt16 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, UInt32 y) { return new Integer(x.value / y); }
    public static Integer operator /(Integer x, UInt64 y) { return new Integer(x.value / y); }
    public static Integer operator %(Integer x, Int16 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, Int32 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, Int64 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, UInt16 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, UInt32 y) { return new Integer(x.value % y); }
    public static Integer operator %(Integer x, UInt64 y) { return new Integer(x.value % y); }
    public static Integer operator +(Integer x, Integer y) { return new Integer(x.value + y.value); }
    public static Integer operator -(Integer x, Integer y) { return new Integer(x.value - y.value); }
    public static Integer operator *(Integer x, Integer y) { return new Integer(x.value * y.value); }
    public static Integer operator /(Integer x, Integer y) { return new Integer(x.value / y.value); }
    public static Integer operator %(Integer x, Integer y) { return new Integer(x.value % y.value); }
    public static bool operator ==(Integer x, Int16 y) { return x.value == y; }
    public static bool operator !=(Integer x, Int16 y) { return x.value != y; }
    public static bool operator ==(Integer x, Int32 y) { return x.value == y; }
    public static bool operator !=(Integer x, Int32 y) { return x.value != y; }
    public static bool operator ==(Integer x, Int64 y) { return x.value == y; }
    public static bool operator !=(Integer x, Int64 y) { return x.value != y; }
    public static bool operator ==(Integer x, UInt16 y) { return x.value == y; }
    public static bool operator !=(Integer x, UInt16 y) { return x.value != y; }
    public static bool operator ==(Integer x, UInt32 y) { return x.value == y; }
    public static bool operator !=(Integer x, UInt32 y) { return x.value != y; }
    public static bool operator ==(Integer x, UInt64 y) { return x.value == y; }
    public static bool operator !=(Integer x, UInt64 y) { return x.value != y; }
    public static bool operator ==(Integer x, Integer y) { return x.value == y.value; }
    public static bool operator !=(Integer x, Integer y) { return x.value != y.value; }
    public override bool Equals(object obj) { return this == (Integer)obj; }
    public override int GetHashCode() { return this.value.GetHashCode(); }
    public override string ToString() { return this.value.ToString(); }
    public static bool operator >(Integer x, Int16 y) { return x.value > y; }
    public static bool operator <(Integer x, Int16 y) { return x.value < y; }
    public static bool operator >(Integer x, Int32 y) { return x.value > y; }
    public static bool operator <(Integer x, Int32 y) { return x.value < y; }
    public static bool operator >(Integer x, Int64 y) { return x.value > y; }
    public static bool operator <(Integer x, Int64 y) { return x.value < y; }
    public static bool operator >(Integer x, UInt16 y) { return x.value > y; }
    public static bool operator <(Integer x, UInt16 y) { return x.value < y; }
    public static bool operator >(Integer x, UInt32 y) { return x.value > y; }
    public static bool operator <(Integer x, UInt32 y) { return x.value < y; }
    public static bool operator >(Integer x, UInt64 y) { return x.value > y; }
    public static bool operator <(Integer x, UInt64 y) { return x.value < y; }
    public static bool operator >(Integer x, Integer y) { return x.value > y.value; }
    public static bool operator <(Integer x, Integer y) { return x.value < y.value; }
    public static bool operator >=(Integer x, Int16 y) { return x.value >= y; }
    public static bool operator <=(Integer x, Int16 y) { return x.value <= y; }
    public static bool operator >=(Integer x, Int32 y) { return x.value >= y; }
    public static bool operator <=(Integer x, Int32 y) { return x.value <= y; }
    public static bool operator >=(Integer x, Int64 y) { return x.value >= y; }
    public static bool operator <=(Integer x, Int64 y) { return x.value <= y; }
    public static bool operator >=(Integer x, UInt16 y) { return x.value >= y; }
    public static bool operator <=(Integer x, UInt16 y) { return x.value <= y; }
    public static bool operator >=(Integer x, UInt32 y) { return x.value >= y; }
    public static bool operator <=(Integer x, UInt32 y) { return x.value <= y; }
    public static bool operator >=(Integer x, UInt64 y) { return x.value >= y; }
    public static bool operator <=(Integer x, UInt64 y) { return x.value <= y; }
    public static bool operator >=(Integer x, Integer y) { return x.value >= y.value; }
    public static bool operator <=(Integer x, Integer y) { return x.value <= y.value; }
    public static Integer operator +(Int16 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(Int32 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(Int64 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(UInt16 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(UInt32 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator +(UInt64 x, Integer y) { return new Integer(x + y.value); }
    public static Integer operator -(Int16 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(Int32 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(Int64 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(UInt16 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(UInt32 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator -(UInt64 x, Integer y) { return new Integer(x - y.value); }
    public static Integer operator *(Int16 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(Int32 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(Int64 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(UInt16 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(UInt32 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator *(UInt64 x, Integer y) { return new Integer(x * y.value); }
    public static Integer operator /(Int16 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(Int32 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(Int64 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(UInt16 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(UInt32 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator /(UInt64 x, Integer y) { return new Integer(x / y.value); }
    public static Integer operator %(Int16 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(Int32 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(Int64 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(UInt16 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(UInt32 x, Integer y) { return new Integer(x % y.value); }
    public static Integer operator %(UInt64 x, Integer y) { return new Integer(x % y.value); }
    public static bool operator ==(Int16 x, Integer y) { return x == y.value; }
    public static bool operator !=(Int16 x, Integer y) { return x != y.value; }
    public static bool operator ==(Int32 x, Integer y) { return x == y.value; }
    public static bool operator !=(Int32 x, Integer y) { return x != y.value; }
    public static bool operator ==(Int64 x, Integer y) { return x == y.value; }
    public static bool operator !=(Int64 x, Integer y) { return x != y.value; }
    public static bool operator ==(UInt16 x, Integer y) { return x == y.value; }
    public static bool operator !=(UInt16 x, Integer y) { return x != y.value; }
    public static bool operator ==(UInt32 x, Integer y) { return x == y.value; }
    public static bool operator !=(UInt32 x, Integer y) { return x != y.value; }
    public static bool operator ==(UInt64 x, Integer y) { return x == y.value; }
    public static bool operator !=(UInt64 x, Integer y) { return x != y.value; }
    public static bool operator >(Int16 x, Integer y) { return x > y.value; }
    public static bool operator <(Int16 x, Integer y) { return x < y.value; }
    public static bool operator >(Int32 x, Integer y) { return x > y.value; }
    public static bool operator <(Int32 x, Integer y) { return x < y.value; }
    public static bool operator >(Int64 x, Integer y) { return x > y.value; }
    public static bool operator <(Int64 x, Integer y) { return x < y.value; }
    public static bool operator >(UInt16 x, Integer y) { return x > y.value; }
    public static bool operator <(UInt16 x, Integer y) { return x < y.value; }
    public static bool operator >(UInt32 x, Integer y) { return x > y.value; }
    public static bool operator <(UInt32 x, Integer y) { return x < y.value; }
    public static bool operator >(UInt64 x, Integer y) { return x > y.value; }
    public static bool operator <(UInt64 x, Integer y) { return x < y.value; }
    public static bool operator >=(Int16 x, Integer y) { return x >= y.value; }
    public static bool operator <=(Int16 x, Integer y) { return x <= y.value; }
    public static bool operator >=(Int32 x, Integer y) { return x >= y.value; }
    public static bool operator <=(Int32 x, Integer y) { return x <= y.value; }
    public static bool operator >=(Int64 x, Integer y) { return x >= y.value; }
    public static bool operator <=(Int64 x, Integer y) { return x <= y.value; }
    public static bool operator >=(UInt16 x, Integer y) { return x >= y.value; }
    public static bool operator <=(UInt16 x, Integer y) { return x <= y.value; }
    public static bool operator >=(UInt32 x, Integer y) { return x >= y.value; }
    public static bool operator <=(UInt32 x, Integer y) { return x <= y.value; }
    public static bool operator >=(UInt64 x, Integer y) { return x >= y.value; }
    public static bool operator <=(UInt64 x, Integer y) { return x <= y.value; }
}
public static class Program
{
    private static bool IntegerFunction(Integer n)
    {
        //code that implements IntegerFunction goes here
        //note that there is NO code that checks the type of n in rum time, because it is NOT needed anymore 
    }
    private static void Main()
    {
        Console.WriteLine("{0}",IntegerFunction(0)); //compile error: there is no overloaded METHOD for objects of type "int" and no implicit conversion from any object, including "int", to "Integer" is known.
        Console.WriteLine("{0}",IntegerFunction(new Integer(0))); //both compiles and no run time error
        Console.WriteLine("{0}",IntegerFunction("string")); //compile error: there is no overloaded METHOD for objects of type "string" and no implicit conversion from any object, including "string", to "Integer" is known.
        Console.WriteLine("{0}",IntegerFunction(new Integer("string"))); //compile error: there is no overloaded CONSTRUCTOR for objects of type "string"
    }
}

নোট করুন যে আপনার কোডটিতে ডায়নামিক ব্যবহার করতে আপনাকে অবশ্যই মাইক্রোসফ্টের রেফারেন্স যুক্ত করতে হবে .সিএসআর্প

.NET ফ্রেমওয়ার্কের সংস্করণটি যদি 4.0 এর চেয়ে কম / নীচে / কম হয় এবং গতিশীল সেই সংস্করণে অপরিজ্ঞাত থাকে তবে আপনাকে পরিবর্তে অবজেক্টটি ব্যবহার করতে হবে এবং সমস্যাটি পূর্ণসংখ্যার ধরণে কাস্টিং করতে হবে, সুতরাং আমি প্রস্তাব দিচ্ছি যে আপনি এখানে ব্যবহার করুন অন্তত .NET 4.0 বা আরও নতুন আপনি যদি পারেন তবে আপনি বস্তুর পরিবর্তে গতিশীল ব্যবহার করতে পারেন ।


2

দুর্ভাগ্যক্রমে। নেট এটি স্থানীয়ভাবে করার কোনও উপায় সরবরাহ করে না।

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

sbyte, byte, short, ushort,int , uint, long, ulong, float, double, decimal, এবংBigInteger

পারফরম্যান্স একটি সংখ্যার ধরণের নির্দিষ্ট সমাধানের সমতুল্য যা আপনাকে দক্ষ জেনেরিক সংখ্যাযুক্ত অ্যালগরিদম তৈরি করতে দেয়।

কোড ব্যবহারের উদাহরণ এখানে।

public static T Sum(T[] items)
{
    T sum = Number.Zero<T>();
    foreach (T item in items)
    {
        sum = Number.Add(sum, item);
    }
    return sum;
}
public static T SumAlt(T[] items)
{
    // implicit conversion to Number<T>
    Number<T> sum = Number.Zero<T>();
    foreach (T item in items)
    {
        // operator support
        sum += item;
    }
    // implicit conversion to T
    return sum;
}

1

অনুশীলনের মূল বক্তব্য কী?

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

static bool IntegerFunction(Int64 value) { }

যদি আপনার ফাংশন কর্মক্ষমতা-সমালোচনামূলক পথে থাকে (খুব সম্ভবত, আইএমও), আপনি সমস্ত প্রয়োজনীয় ফাংশনগুলির জন্য ওভারলোড সরবরাহ করতে পারেন।

static bool IntegerFunction(Int64 value) { }
...
static bool IntegerFunction(Int16 value) { }

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

1

আমি একটি জেনেরিক ব্যবহার করব যা আপনি বাহ্যিকভাবে পরিচালনা করতে পারবেন ...

/// <summary>
/// Generic object copy of the same type
/// </summary>
/// <typeparam name="T">The type of object to copy</typeparam>
/// <param name="ObjectSource">The source object to copy</param>
public T CopyObject<T>(T ObjectSource)
{
    T NewObject = System.Activator.CreateInstance<T>();

    foreach (PropertyInfo p in ObjectSource.GetType().GetProperties())
        NewObject.GetType().GetProperty(p.Name).SetValue(NewObject, p.GetValue(ObjectSource, null), null);

    return NewObject;
}

1

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

আমি কিছু চাই

public struct Foo<T>
{
    public T Value{ get; private set; }

    public static Foo<T> operator +(Foo<T> LHS, Foo<T> RHS)
    {
        return new Foo<T> { Value = LHS.Value + RHS.Value; };
    }
}

.Net4 গতিশীল রানটাইম টাইপিং ব্যবহার করে আমি এই সমস্যাটি নিয়ে কাজ করেছি।

public struct Foo<T>
{
    public T Value { get; private set; }

    public static Foo<T> operator +(Foo<T> LHS, Foo<T> RHS)
    {
        return new Foo<T> { Value = LHS.Value + (dynamic)RHS.Value };
    }
}

ব্যবহার সম্পর্কে দুটি জিনিস dynamicহয়

  1. কর্মক্ষমতা. সমস্ত মান ধরণের বক্স হয়ে যায়।
  2. রানটাইম ত্রুটি। আপনি সংকলকটিকে "বীট" করেন তবে সুরক্ষাটি হারিয়ে ফেলুন। যদি জেনেরিক ধরণের অপারেটর সংজ্ঞায়িত না হয় তবে কার্যকর করার সময় একটি ব্যতিক্রম ছুঁড়ে ফেলা হবে।

1

.NET সংখ্যাসূচক আদিম ধরণের কোনও সাধারণ ইন্টারফেস ভাগ করে না যা তাদের গণনার জন্য ব্যবহার করতে দেয়। এটা আপনার নিজের ইন্টারফেসগুলি (যেমন সংজ্ঞায়িত করতে সম্ভব হবে ISignedWholeNumber) যা অপারেশন সম্পাদন করবে, স্ট্রাকচার যা একটি একক ধারণ সংজ্ঞায়িত Int16, Int32ইত্যাদি এবং যারা ইন্টারফেসগুলি বাস্তবায়ন, এবং তারপর পদ্ধতি যা করতে বাধ্য জেনেরিক ধরনের গ্রহন করেছি ISignedWholeNumber, কিন্তু সাংখ্যিক মান রূপান্তর করতে হচ্ছে আপনার কাঠামোর ধরণের সম্ভবত উপদ্রব হবে।

একটি বিকল্প পদ্ধতির স্ট্যাটিক বর্গ সংজ্ঞায়িত করতে হবে Int64Converter<T>একটি স্ট্যাটিক সম্পত্তি সঙ্গে bool Available {get;};এবং জন্য স্ট্যাটিক প্রতিনিধিদের Int64 GetInt64(T value), T FromInt64(Int64 value), bool TryStoreInt64(Int64 value, ref T dest)। শ্রেণি নির্মাতা পরিচিত প্রকারের জন্য ডেলিগেটগুলি লোড করার জন্য হার্ড-কোডড ব্যবহার করতে পারে এবং Tসঠিক নাম এবং স্বাক্ষর সহ টাইপ প্রয়োগকারী পদ্ধতিগুলি পরীক্ষা করতে রিফ্লেকশন ব্যবহার করতে পারে (যদি এটি স্ট্রাকের মতো কিছু থাকে যা Int64একটি সংখ্যার প্রতিনিধিত্ব করে, তবে রয়েছে একটি কাস্টম ToString()পদ্ধতি)। এই পদ্ধতিটি কম্পাইল-টাইম টাইপ-চেকিংয়ের সাথে যুক্ত সুবিধাগুলি হারাবে, তবে বক্সিং অপারেশনগুলি এড়াতে সক্ষম হবে এবং প্রতিটি ধরণের কেবল একবার "পরীক্ষা করা" হবে। এর পরে, এই ধরণের সাথে সম্পর্কিত ক্রিয়াকলাপগুলি একটি প্রতিনিধি প্রেরণের সাথে প্রতিস্থাপন করা হবে।


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

1

আমার একটি অনুরূপ পরিস্থিতি ছিল যেখানে আমার সংখ্যার প্রকার এবং স্ট্রিংগুলি পরিচালনা করতে হবে; কিছুটা উদ্ভট মিশ্রণ মনে হয় তবে আপনি সেখানে যান।

আবার অনেকের মতো আমিও প্রতিবন্ধকতার দিকে নজর দিয়েছি এবং এটি সমর্থন করার জন্য একটি গুচ্ছ ইন্টারফেস নিয়ে এসেছি। তবে, ক) এটি ১০০% জলরোধক এবং খ) নয়, এই দীর্ঘস্থায়ী সীমাবদ্ধতার তালিকার দিকে নতুন যে কেউ নজর দিচ্ছেন তা অবিলম্বে খুব বিভ্রান্ত হবে।

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

public static string DoSomething(this int input, ...) => DoSomethingHelper(input, ...);
public static string DoSomething(this decimal input, ...) => DoSomethingHelper(input, ...);
public static string DoSomething(this double input, ...) => DoSomethingHelper(input, ...);
public static string DoSomething(this string input, ...) => DoSomethingHelper(input, ...);

private static string DoSomethingHelper<T>(this T input, ....)
{
    // complex logic
}

0

আপনি যদি চান তার মধ্যে একটি সংখ্যার টাইপ ব্যবহার করা হয় , আপনি সি ++ এর সাথে একটি উলামের অনুরূপ কিছু তৈরি করতে বিবেচনা করতে পারেন using

সুতরাং খুব জেনেরিক পরিবর্তে

T ComputeSomething<T>(T value1, T value2) where T : INumeric { ... }

আপনি থাকতে পারে

using MyNumType = System.Double;
T ComputeSomething<MyNumType>(MyNumType value1, MyNumType value2) { ... }

আপনি সহজেই থেকে যেতে অনুমতি পারে doubleথেকে intঅথবা অন্যদের প্রয়োজনে, কিন্তু আপনি ব্যবহার করতে পারব না ComputeSomethingসঙ্গে doubleএবং intএকই প্রোগ্রামে।

তবে কেন সব doubleজায়গায় প্রতিস্থাপন করা হবে না int? আপনার পদ্ধতি ব্যবহার করতে পারেন কারণ doubleকিনা ইনপুট doubleবা int। উপনামটি আপনাকে সঠিকভাবে জানতে দেয় যে কোন পরিবর্তনশীল গতিশীল প্রকারটি ব্যবহার করে ।


0

বিষয় পুরানো তবে ভবিষ্যতের পাঠকদের জন্য:

এই বৈশিষ্ট্যটি দৃ tight়ভাবে সম্পর্কিত Discriminated Unionsযা এখন পর্যন্ত সি # তে প্রয়োগ করা হয়নি। আমি এখানে এটির সমস্যাটি পেয়েছি:

https://github.com/dotnet/csharplang/issues/113

এই সমস্যাটি এখনও উন্মুক্ত এবং এর বৈশিষ্ট্যটির জন্য পরিকল্পনা করা হয়েছে C# 10

তবুও আমাদের আরও কিছুটা অপেক্ষা করতে হবে, তবে মুক্তি দেওয়ার পরে আপনি এটি এইভাবে করতে পারেন:

static bool IntegerFunction<T>(T value) where T : Int16 | Int32 | Int64 | ...

-11

আমি মনে করি আপনি জেনেরিকগুলি ভুল বুঝছেন। আপনি যে অপারেশনটি করার চেষ্টা করছেন সেটি যদি নির্দিষ্ট ডেটা ধরণের জন্য কেবল ভাল হয় তবে আপনি "জেনেরিক" কিছু করছেন না।

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

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

অন্য সব কিছুতে ব্যর্থ হয়ে, টাইপ অবজেক্টের একটি প্যারামিটার ব্যবহার করা যেতে পারে এবং তারপরে আপনাকে প্যারামিটারের ধরণটি পরীক্ষা করতে হবে এবং উপযুক্ত পদক্ষেপ নিতে হবে বা একটি ব্যতিক্রম ছুঁড়ে ফেলতে হবে।


10
একটি শ্রেণীর হিস্টোগ্রাম <T> বিবেচনা করুন। এটি একটি জেনেরিক প্যারামিটার নিতে দেয় তা বোঝা যায়, তাই সংকলক এটি বাইটস, ইনটস, ডাবলস, দশমিক, বিগআইন্ট, ... এর জন্য অনুকূল করতে পারে তবে একই সাথে আপনি প্রতিরোধ করতে হবে যে আপনি একটি তৈরি করতে পারেন, বলুন, হিস্টোগ্রাম <হ্যাশেট >, কারণ - ট্রোন দিয়ে কথা বলা - এটি গণনা করে না। (আক্ষরিক :))
রোদ

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