2012-06-08 11 views
7

क्या सी # जेनेरिक में बुनियादी अंकगणित (कम से कम अतिरिक्त) लागू करना संभव है, जैसे आप with C++ templates कर सकते हैं? मैं उन्हें उठाने और काम करने के लिए थोड़ी देर के लिए कोशिश कर रहा हूं, लेकिन सी # आपको एक ही जेनेरिक प्रकार की कई बार घोषित नहीं करता है, जैसे आप टेम्पलेट्स के साथ कर सकते हैं।जेनेरिक में अंकगणित कार्यान्वित?

व्यापक googling एक उत्तर प्रदान नहीं किया था।

संपादित करें: धन्यवाद, लेकिन जो मैं खोज रहा हूं वह संकलन समय पर अंकगणित करने का एक तरीका है, जेनेरिक प्रकारों में चर्च अंकों जैसे कुछ एम्बेड करना। यही कारण है कि मैंने उस आलेख को जोड़ा जो मैंने किया था। सामान्य प्रकारों के उदाहरणों पर अंकगणित जेनेरिक प्रकार, अंकगणित नहीं।

+3

दुर्भाग्य से, प्रकार बाधा आप की आवश्यकता करने के लिए उस प्रकार arithmethic ऑपरेटरों का समर्थन करता है की अनुमति नहीं है। मुझे दिलचस्प लगता है कि बीसीएल स्रोत कोड में उदा। 'Int32' आपको विरासत सूची में 'IArithmetic ' इंटरफ़ेस मिलेगा जिस पर टिप्पणी की गई है। यह मेरे हिस्से पर शुद्ध अटकलें है, लेकिन यदि माइक्रोसॉफ्ट ने बीसीएल में उस इंटरफ़ेस को सक्षम किया है तो आप शायद अंकगणितीय के साथ अपनी जेनेरिक कक्षाएं लिखने की अनुमति देने के लिए 'IArithmetic ' को बाध्यता के रूप में निर्दिष्ट कर सकते हैं। –

+0

इसी तरह के प्रश्न से लिंक करें: http://stackoverflow.com/q/4039694/613130 ​​ – xanatos

उत्तर

4

दुर्भाग्य से आप सामान्य प्रकार पर अंकगणितीय आपरेशनों उपयोग नहीं कर सकते

T Add(T a, T b) 
{ 
    return a + b; // compiler error here 
} 

काम नहीं करेगा:


मुझे यकीन है कि तुम क्या मतलब है, यह काम करता है "एक ही सामान्य प्रकार कई बार घोषित" नहीं कर रहा हूँ सी # में!

लेकिन आप अपने स्वयं के संख्यात्मक प्रकार बना सकते हैं और ऑपरेटरों को अधिभारित कर सकते हैं (अंकगणित समानता और implicit, explicit)। यह आपको उनके साथ काफी प्राकृतिक तरीके से काम करने देता है। हालांकि आप जेनेरिक के साथ विरासत पदानुक्रम नहीं बना सकते हैं। आपको एक गैर जेनेरिक बेस क्लास या इंटरफेस का उपयोग करना होगा।

मैंने अभी इसे एक वेक्टर प्रकार के साथ किया है।यहाँ एक छोटा संस्करण:

public class Vector 
{ 
    private const double Eps = 1e-7; 

    public Vector(double x, double y) 
    { 
     _x = x; 
     _y = y; 
    } 

    private double _x; 
    public double X 
    { 
     get { return _x; } 
    } 

    private double _y; 
    public double Y 
    { 
     get { return _y; } 
    } 

    public static Vector operator +(Vector a, Vector b) 
    { 
     return new Vector(a._x + b._x, a._y + b._y); 
    } 

    public static Vector operator *(double d, Vector v) 
    { 
     return new Vector(d * v._x, d * v._y); 
    } 

    public static bool operator ==(Vector a, Vector b) 
    { 
     if (ReferenceEquals(a, null)) { 
      return ReferenceEquals(b, null); 
     } 
     if (ReferenceEquals(b, null)) { 
      return false; 
     } 
     return Math.Abs(a._x - b._x) < Eps && Math.Abs(a._y - b._y) < Eps; 
    } 

    public static bool operator !=(Vector a, Vector b) 
    { 
     return !(a == b); 
    } 

    public static implicit operator Vector(double[] point) 
    { 
     return new Vector(point[0], point[1]); 
    } 

    public static implicit operator Vector(PointF point) 
    { 
     return new Vector(point.X, point.Y); 
    } 

    public override int GetHashCode() 
    { 
     return _x.GetHashCode()^_y.GetHashCode(); 
    } 

    public override bool Equals(object obj) 
    { 
     var other = obj as Vector; 
     return other != null && Math.Abs(other._x - _x) < Eps && Math.Abs(other._y - _y) < Eps; 
    } 

    public override string ToString() 
    { 
     return String.Format("Vector({0:0.0000}, {1:0.0000})", _x, _y); 
    } 
} 
+0

आपका क्या मतलब है "संरचना 'बाधाओं की अनुमति नहीं है"? –

+0

आप वास्तव में कर सकते हैं। देखें [टाइप पैरामीटर्स पर प्रतिबंध (सी # प्रोग्रामिंग गाइड)] (http://msdn.microsoft.com/en-us/library/d5x73970.aspx)। –

+0

@AdamHouldsworth: स्ट्रक्चर इंटरफेस को कार्यान्वित कर सकते हैं! चूंकि structs एक-दूसरे से उत्तराधिकारी नहीं हो सकते हैं, इसलिए एक निश्चित संरचना प्रकार को प्रतिबंधित करना सामान्य जेनेरिक पैरामीटर नहीं होगा (या आपके पास एक वैध सामान्य प्रकार पैरामीटर होगा, अर्थात् यह एक संरचना)! –

3

यदि मेरा उत्तर ऑफ-किटर लगता है तो कृपया अधिक स्पष्टीकरण प्रदान करने के लिए स्वतंत्र महसूस करें।

कम से कम सी # भाषा में ऑपरेटरों पर कोई सामान्य बाधा नहीं है। जैसा कि जॉन स्कीट Unconstrained Melody के साथ साबित हुआ है, बाधाएं वास्तव में सीएलआर में पूरी तरह वैध हो सकती हैं।

बाधाओं के साथ आप सबसे अच्छा कर सकते हैं इंटरफेस/कस्टम कक्षाएं जो आपको आवश्यक कार्यों का पर्दाफाश करती हैं। आप आदिम प्रदान नहीं कर पाएंगे (जब तक कि आप शायद implicit ऑपरेटर को भी लागू नहीं करते), लेकिन कम से कम आप गणित के हिस्से के लिए जेनेरिक कोड बना सकते हैं।

जेनेरिक बाधाएं संकलक को सबसे कम आम denominator (जैसा कि बाधा या कमी के द्वारा निर्दिष्ट) के आधार पर उपलब्ध सदस्यों को अनुमान लगाने की अनुमति देता है। अधिकांश समय, जेनेरिक अनियंत्रित होते हैं और इस प्रकार आपको केवल object अर्थशास्त्र प्रदान करते हैं।


वैकल्पिक रूप से, बाधाओं के उपयोग से बचें और dynamic का उपयोग अस्थायी रूप से सामान्य चर की दुकान और फिर इस धारणा बनाना (बतख टाइपिंग के माध्यम से) के लिए यह प्रासंगिक ऑपरेटरों है:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var result = Add<int, long, float>(1, 2); 
     Console.WriteLine(result); // 3 
     Console.WriteLine(result.GetType().FullName); // System.Single 
     Console.Read(); 
    } 

    static T3 Add<T1, T2, T3>(T1 left, T2 right) 
    { 
     dynamic d1 = left; 
     dynamic d2 = right; 
     return (T3)(d1 + d2); 
    } 
} 

यह डीएलआर शामिल है और होगा कुछ प्रदर्शन ओवरहेड (मेरे पास सटीक आंकड़े नहीं हैं), खासकर यदि आप प्रदर्शन-महत्वपूर्ण होने की गणना करना चाहते हैं।

class Tuple<T1, T2> // etc. 

var myTuple = new Tuple<int, int>(1, 2); 
0

मित्र, सी # में यह करने के लिए सहज ज्ञान युक्त जवाब RTTI और आगे और पीछे वस्तु वर्ग

enter code here 

class MyMath 
{ 
    public static T Add<T>(T a, T b) where T: struct 
    { 
     switch (typeof(T).Name) 
     { 
      case "Int32": 
       return (T) (object)((int)(object)a + (int)(object)b); 
      case "Double": 
       return (T)(object)((double)(object)a + (double)(object)b); 
      default: 
       return default(T); 
     } 
    } 
} 

class Program 
{ 
    public static int Main() 
    { 
     Console.WriteLine(MyMath.Add<double>(3.6, 2.12)); 
     return 0; 
    } 
} 
+0

मैं सी # में एक नौसिखिया हूं और इसलिए कोई साधारण स्पष्टीकरण महत्वपूर्ण है इसलिए यदि कोई वोट देता है, तो मैं उस पर टिप्पणी की सराहना करता हूं! अब, क्या कोई (अन्य) कृपया बता सकता है कि इस जवाब को वोट क्यों मिला है? यह दृष्टिकोण सही क्यों नहीं है? – Celdor

+1

@Celdor: सबसे पहले, यह धीमा होने जा रहा है, क्योंकि आप आरटीटीआई कर रहे हैं और स्ट्रिंग की तुलना कर रहे हैं। दूसरा, यह वास्तव में सामान्य नहीं है अगर मुझे हर प्रकार मैन्युअल रूप से जोड़ना है ... –

+1

हाल ही में जिट ने ऑप्टिमाइज़ेशन डिटेक्टिंग टाइपोफ (टी) और आरटीटीआई स्थितियों के आधार पर मृत शाखाओं को हटा दिया है। उचित समाधान के साथ यह समाधान अन्य उत्तरों की तुलना में तेज़ी से चला सकता है। – Luca

-1

हाँ से कास्टिंग है, यह गतिशील प्रकार चर का उपयोग करके किया जा सकता है ।

उदाहरण:

T Add(T value1, T value2) 
{   
     dynamic a = value1; 
     dynamic b = value2; 
     return (a + b); 
} 

अधिक संदर्भ के लिए कृपया click here

संबंधित मुद्दे