2010-06-30 23 views
17

मैंने इस प्रश्न के लिए कुछ समान धागे देखे हैं, लेकिन उनमें से कोई भी वास्तव में उस प्रश्न का उत्तर नहीं देता जिसे मैं पूछना चाहता हूं।सी #: इंटरफेस में एनम्स

स्टार्टर्स के लिए, दुर्भाग्यवश मैं मौजूदा एपीआई कोड के साथ काम कर रहा हूं, इसलिए दुख की बात है, जबकि मैं जो पूछ रहा हूं उसे करने का एक बेहतर तरीका हो सकता है, मैं इसे उसी तरह से करने के लिए बंद कर रहा हूं क्योंकि यह ऐसा है पिछड़ा संगतता गैर-विचारणीय है।

मेरे पास एक प्रतिक्रिया वर्ग है जिसमें वर्तमान में त्रुटि कोड और स्ट्रिंग विवरण के लिए एक enum शामिल है। त्रुटि कोड उन प्रतिक्रियाओं के एकदम सही और पूर्ण सेट को परिभाषित करते हैं जो सभी बहुत ही अर्थात् उन परिचालनों के साथ मिलते हैं जहां उनका उपयोग किया जाता है।

असुविधाजनक रूप से, मुझे अब एपीआई ऑब्जेक्ट्स के एक समान सेट के लिए एक अलग वर्कफ़्लो जोड़ना होगा, और इसके लिए एक स्ट्रिंग विवरण की आवश्यकता होगी, जो ठीक है, लेकिन एक एनम त्रुटि कोड भी है जो त्रुटि कोडों का एक पूरी तरह से असंबंधित सेट शामिल है। त्रुटि कोड (और ऑब्जेक्ट मॉडल के अन्य पहलुओं) का उपयोग बहुत से वर्गों में किया जाएगा, इसलिए इंटरफ़ेस जाने के लिए अच्छा लगेगा ताकि मैं ऑब्जेक्ट को उसी ढांचे के माध्यम से चला सकूं।

यहां एक इरादा अनुबंध करना है जो कहता है "मेरे पास एक त्रुटि कोड है, और उस त्रुटि कोड का विवरण है।"

लेकिन, जैसा कि तक मुझे पता है वहाँ एक इंटरफेस जैसे

public interface IError 
{ 
    enum ErrorCode; 
    string Description; 
} 

है और न ही करने के लिए एक आइटम जोड़ने के लिए कोई तरीका नहीं है

public interface IError<T> where T: enum 
{ 
    T ErrorCode; 
    string Description; 
} 

किसी को व्यक्त करने के लिए एक तरह से हर कुछ के खिलाफ चलाने है इससे पहले की तरह?

+0

क्या आपरेशन आप की आवश्यकता होगी इस इंटरफ़ेस द्वारा प्रदान की गई त्रुटि कोड पर प्रदर्शन करने के लिए? यदि आपको एनम-विशिष्ट व्यवहार तक पहुंच की आवश्यकता नहीं है, तो आप त्रुटि कोड को बिना किसी नुकसान के किसी भी प्रकार के होने की अनुमति दे सकते हैं। –

उत्तर

13

हां, मैंने इसके खिलाफ भाग लिया है। इस विशेष स्थिति में नहीं, लेकिन अन्य स्टैक ओवरफ़्लो प्रश्नों में, like this one। (मैं, डुप्लिकेट के रूप में यह एक बंद करने के लिए मतदान कर रहा हूँ नहीं के रूप में यह थोड़ा अलग है।)

यह अपने सामान्य इंटरफ़ेस व्यक्त करने के लिए संभव है - बस सी # में नहीं। आप आईएल में कोई समस्या नहीं कर सकते हैं। मुझे आशा है कि सीमा सी # 5 में हटा दी जा सकती है। सी # कंपाइलर वास्तव में बाधा को पूरी तरह से सही तरीके से संभालता है, जहां तक ​​मैंने देखा है।

यदि आप वास्तव में इसे एक विकल्प के रूप में जाना चाहते हैं, तो आप Unconstrained Melody में इसी तरह के कोड का उपयोग कर सकते हैं, एक लाइब्रेरी जो मैंने प्राप्त की है जो इस हार्ड-टू-प्रोडक्शन बाधा के साथ विभिन्न विधियों का खुलासा करती है। यह आईएल रीराइटिंग का प्रभावी ढंग से उपयोग करता है - यह कच्चा है, लेकिन यह यूएम के लिए काम करता है और शायद आपके लिए भी काम करेगा। आप शायद इंटरफ़ेस को एक अलग असेंबली में रखना चाहते हैं, जो कुछ हद तक अजीब होगा।

बेशक, आप अपने इंटरफ़ेस को केवल T : struct कर सकते हैं ... यह आदर्श नहीं होगा, लेकिन कम से कम कुछ हद तक को बाधित करेगा। जब तक आप यह सुनिश्चित कर सकें कि इसका दुरुपयोग नहीं किया जा रहा था, तो यह उचित रूप से अच्छा काम करेगा।

1

public interface IError<T> where T: enum लिखने में असमर्थता कुछ ऐसा है जो हमने वर्षों से शिकायत की है। अभी तक उस पर कोई प्रगति नहीं हुई है।

मैं आम तौर पर public interface IError<T> लिखना समाप्त करता हूं और कार्यान्वयनकर्ता के लिए एक नोट छोड़ देता हूं कि टी एक enum होना चाहिए।

1

यदि मैं समझता हूं कि आप क्या करना चाहते हैं, तो हाँ, एक इंटरफ़ेस को परिभाषित करने का कोई तरीका नहीं है जिसमें इसके सदस्यों में से एक गैर-विशिष्ट enum शामिल है।आपका दूसरा उदाहरण करीब है, लेकिन आप T के प्रकार को struct पर सीमित करने के लिए सीमित हैं, जो किसी भी मान प्रकार की अनुमति देगा। उस बिंदु पर, आपको केवल इंटरफेस के ज्ञान पर भरोसा करना होगा ताकि लोगों को अपेक्षित प्रकार T को एनम होना चाहिए। लेकिन सी # आप इसे का लाभ लेने के लिए अनुमति नहीं देता

public interface IError<TEnum> where T: struct 
{ 
    T ErrorCode; 
    string Description; 
} 
8

जॉन स्कीट उल्लेख किया है, आधार आईएल जेनरिक बाधित करने का समर्थन करता enums होने के लिए,: आप संभवतः TEnum या TErrorValue रूप T को परिभाषित करते हुए यह थोड़ा स्पष्ट कर सकता है।

एफ # इस तरह की बाधा की अनुमति देता है, हालांकि। इसके अलावा, यदि इंटरफ़ेस को F # में परिभाषित किया गया है, तो बाधा सी # कोड में लागू की जाएगी जो इंटरफ़ेस लागू करती है। आप अपने समाधान में भाषाओं का मिश्रण करने के लिए तैयार कर रहे हैं, कुछ इस तरह ठीक काम करना चाहिए:

type IError<'T when 'T :> System.Enum and 'T : struct> = 
    abstract member Error : 'T 
    abstract member Description : string 

आप एक एफ # परियोजना में इस डाल दिया और अपनी सी # परियोजना, अपने सी # कोड है कि इंटरफ़ेस को लागू करता है से इसे संदर्भ हैं गैर-एनम प्रकार के साथ इसका उपयोग करने के किसी भी प्रयास पर सी # कंपाइलर त्रुटि का कारण बन जाएगा।

+0

सी # 2.0 और वीएस2005 के लिए यह समाधान कितना सुलभ है? मैं अनुमान लगा रहा हूं ... बहुत नहीं? सुंदर मीठा लग रहा है, मुझे यकीन नहीं है कि मैं लाभ लेने में सक्षम हूं। – bwerks

+1

परोक्ष रूप से, आप यह कर सकते हैं। आपको मुफ्त [VS2008 शैल] स्थापित करना होगा (http://www.microsoft.com/downloads/details.aspx?FamilyId=40646580-97FA-4698-B65F-620D4B4B1ED7&displaylang=en) और [F # 2.0] (http : //www.microsoft.com/downloads/details.aspx FamilyID = 444005fb-e627-4feb-b51d-13d6a3b4b8ed और displaylang = hi)। फिर आप अपने इंटरफ़ेस को एफ # प्रोजेक्ट लक्ष्यीकरण सीएलआर 2.0 में परिभाषित कर सकते हैं, बाइनरी बना सकते हैं, और उन्हें VS2005 में C# 2 से संदर्भित कर सकते हैं। यदि आप अक्सर अपने इंटरफेस को नहीं बदलते हैं, तो आप अधिकतर इंस्टॉल किए गए सब कुछ को अनदेखा कर सकते हैं। –

+0

टी को मूल्य प्रकार होने के लिए बाध्य होने की भी आवश्यकता है, अन्यथा System.Enum ठीक होगा। –

3

आप एक अलग तरीके से अपने दृष्टिकोण के साथ जा सकते हैं:

public interface IError 
{ 
    Enum ErrorCode; 
    string Description; 
} 

System.Enum, अपने सभी enums के आधार वर्ग है, ताकि इसे संभाल चाहिए, लेकिन अपने दूर से अर्थपूर्ण जा रहा है।

यहां सही दृष्टिकोण है कि आप अपने स्वयं के एनम कक्षाएं और बेस एनम कक्षा का निर्माण करें। के लिए उदाहरण के लिए।,

public class ErrorFlag // base enum class 
{ 
    int value; 

    ErrorFlag() 
    { 

    } 

    public static implicit operator ErrorFlag(int i) 
    { 
     return new ErrorFlag { value = i }; 
    } 

    public bool Equals(ErrorFlag other) 
    { 
     if (ReferenceEquals(this, other)) 
      return true; 

     if (ReferenceEquals(null, other)) 
      return false; 

     return value == other.value; 
    } 

    public override bool Equals(object obj) 
    { 
     return Equals(obj as ErrorFlag); 
    } 

    public static bool operator ==(ErrorFlag lhs, ErrorFlag rhs) 
    { 
     if (ReferenceEquals(lhs, null)) 
      return ReferenceEquals(rhs, null); 

     return lhs.Equals(rhs); 
    } 

    public static bool operator !=(ErrorFlag lhs, ErrorFlag rhs) 
    { 
     return !(lhs == rhs); 
    } 

    public override int GetHashCode() 
    { 
     return value; 
    } 

    public override string ToString() 
    { 
     return value.ToString(); 
    } 
} 

public interface IError 
{ 
    ErrorFlag ErrorCode; 
    string Description; 
} 

अब बजाय अपनी खुद की त्रुटि enums होने के, अपने खुद के ErrorFlag कक्षाएं लिखें।

public sealed class ReportErrorFlag : ErrorFlag 
{ 
    //basically your enum values 
    public static readonly ErrorFlag Report1 = 1; 
    public static readonly ErrorFlag Report2 = 2; 
    public static readonly ErrorFlag Report3 = 3; 

    ReportErrorFlag() 
    { 

    } 
} 

public sealed class DataErrorFlag : ErrorFlag 
{ 
    //basically your enum values 
    public static readonly ErrorFlag Data1 = 1; 
    public static readonly ErrorFlag Data2 = 2; 
    public static readonly ErrorFlag Data3 = 3; 

    DataErrorFlag() 
    { 

    } 
} 

// etc 

अब आप अपने मुख्य वर्गों:

public class ReportError : IError 
{ 
    // implementation 
} 

public class DataError : IError 
{ 
    // implementation 
} 

या अन्यथा,

public class ErrorFlag // base enum class 
{ 
    internal int value { get; set; } 

    public bool Equals(ErrorFlag other) 
    { 
     if (ReferenceEquals(this, other)) 
      return true; 

     if (ReferenceEquals(null, other)) 
      return false; 

     return value == other.value; 
    } 

    public override bool Equals(object obj) 
    { 
     return Equals(obj as ErrorFlag); 
    } 

    public static bool operator ==(ErrorFlag lhs, ErrorFlag rhs) 
    { 
     if (ReferenceEquals(lhs, null)) 
      return ReferenceEquals(rhs, null); 

     return lhs.Equals(rhs); 
    } 

    public static bool operator !=(ErrorFlag lhs, ErrorFlag rhs) 
    { 
     return !(lhs == rhs); 
    } 

    public override int GetHashCode() 
    { 
     return value; 
    } 

    public override string ToString() 
    { 
     return value.ToString(); 
    } 
} 

public interface IError<T> where T : ErrorFlag 
{ 
    T ErrorCode { get; set; } 
    string Description { get; set; } 
} 

//enum classes 
public sealed class ReportErrorFlag : ErrorFlag 
{ 
    //basically your enum values 
    public static readonly ReportErrorFlag Report1 = new ReportErrorFlag { value = 1 }; 
    public static readonly ReportErrorFlag Report2 = new ReportErrorFlag { value = 2 }; 
    public static readonly ReportErrorFlag Report3 = new ReportErrorFlag { value = 3 }; 

    ReportErrorFlag() 
    { 

    } 
} 

public sealed class DataErrorFlag : ErrorFlag 
{ 
    //basically your enum values 
    public static readonly DataErrorFlag Data1 = new DataErrorFlag { value = 1 }; 
    public static readonly DataErrorFlag Data2 = new DataErrorFlag { value = 2 }; 
    public static readonly DataErrorFlag Data3 = new DataErrorFlag { value = 3 }; 

    DataErrorFlag() 
    { 

    } 
} 

//implement the rest 

enum की कमी होने के बदसूरत तरीका है करने के लिए, को देखने के Anyone know a good workaround for the lack of an enum generic constraint?

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