किसी को भी एक सामान्य सामान्य बाधा की कमी के लिए एक अच्छा कामकाज पता है?

मैं जो कुछ करना चाहता हूं वह ऐसा कुछ है: मेरे पास संयुक्त ध्वजांकित मानों के साथ enums है।

public static class EnumExtension
{
    public static bool IsSet( this T input, T matchTo ) 
        where T:enum //the constraint I want that doesn't exist in C#3
    {    
        return (input & matchTo) != 0;
    }
}

तो मैं कर सकता था:

MyEnum tester = MyEnum.FlagA | MyEnum.FlagB

if( tester.IsSet( MyEnum.FlagA ) )
    //act on flag a

दुर्भाग्यवश सी # की सामान्य जहां बाधाओं में कोई निर्बाध प्रतिबंध नहीं है, केवल वर्ग और संरचना है। सी # एनट्रम्स को structs के रूप में नहीं देखता है (भले ही वे मूल्य प्रकार हैं) इसलिए मैं इस तरह के एक्सटेंशन प्रकार नहीं जोड़ सकता।

किसी को भी कामकाज पता है?

0
ro fr bn
@dmihailescu - स्वीकृत उत्तर में @ जोन स्कीट का कहीं अधिक पूर्ण और विस्तृत समाधान देखें।
जोड़ा लेखक Keith, स्रोत
आपका क्या मतलब है? सी # एनट्रम्स को structs के रूप में नहीं देखता है ?? आप enum प्रकारों को टाइप पैरामीटर के रूप में उपयोग कर सकते हैं जो struct को ठीक से बाध्य हैं।
जोड़ा लेखक Timwi, स्रोत
कीथ: UnconstrainedMelody के संस्करण 0.0.0.2 डाउनलोड करें - मैंने HasAll और HasAny लागू किया है। का आनंद लें।
जोड़ा लेखक Jon Skeet, स्रोत
इस uservoice idea , यदि आप इसे एक दिन में .NET में अंतर्निहित देखना चाहते हैं।
जोड़ा लेखक Matthieu, स्रोत
इस आलेख को यहां देखें: codeproject.com/KB/cs/ExtendEnum.aspx 'IsValidEnumValue' या 'IsFlagsEnumDefined' विधियां शायद आपके प्रश्न का उत्तर हैं।
जोड़ा लेखक dmihailescu, स्रोत
@dmihailescu: नहीं, वह कोड प्रोजेक्ट एक अलग, अधिक जटिल समस्या को संबोधित कर रहा है: यह निर्धारित करना कि किसी दिया गया मान किसी दिए गए एनम के लिए मान्य मान है या नहीं। जैसे यदि आपको मूल्य "9" दिया गया है, तो क्या यह आपके एनम के लिए मान्य है? (नहीं, यदि आपके पास केवल 3 ध्वज बिट्स हैं)। ओपी फ्लैग एनम पर सरल बिट ऑपरेशंस को सामान्य बनाने की कोशिश कर रहा है। यदि आपके पास एक विशिष्ट एनम प्रकार है, तो ये ऑपरेशन एक-लाइनर हैं। जैसे फ्लैग बिट को साफ़ करना value = value और (~ MyEnum.FlagA) जैसा कुछ है। लेकिन यह हर बार लिखने के लिए दर्द होता है, इसलिए एक बार जेनेरिक तरीकों को लिखना
जोड़ा लेखक ToolmakerSteve, स्रोत
सी # 7.3 enum बाधाओं को प्रस्तुत करता है।
जोड़ा लेखक Marc Sigrist, स्रोत

11 उत्तर

डैरेन, यह काम करेगा यदि प्रकार विशिष्ट गणनाएं थीं - काम करने के लिए सामान्य गणना के लिए आपको उन्हें बुलियन गणित करने के लिए इनट्स (या अधिक संभावना है) में डालना होगा:

public static bool IsSet( this Enum input, Enum matchTo )
{
    return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}
0
जोड़ा
ध्यान दें कि Convert.ToUInt32 एक enum के साथ उपयोग किया जाएगा Convert.ToUInt32 (ऑब्जेक्ट) अधिभार का उपयोग करेगा, जिसका अर्थ है कि सीएलआर पहले को पास करने से पहले इन मानों को बॉक्स करेगा। ToUInt32 विधि। ज्यादातर मामलों में इससे कोई फर्क नहीं पड़ता, लेकिन यह जानना अच्छा होता है कि यदि आप प्रति सेकंड लाखों enums पार्स करने के लिए इस तरह कुछ उपयोग कर रहे हैं तो आप जीसी को व्यस्त रखेंगे।
जोड़ा लेखक Groo, स्रोत
और यदि आपके पास हास्यास्पद संख्या में झंडे हैं, तो आप तर्कों और Getvert.ToUint64() पर GetTypeCode() को कॉल कर सकते हैं।
जोड़ा लेखक Kit, स्रोत
बहुत बढ़िया, 'Enum` और Convert.ToUInt32 का संयोजन मुझे कहीं और नहीं मिला। AFAIK, यह एकमात्र सभ्य प्री-नेट -4 समाधान है जो वीबी में भी काम करता है। बीटीडब्ल्यू, यदि matchTo में कई ध्वज बिट्स हो सकते हैं, तो ! = 0 को == कनवर्ट करें। TUUInt32 (matchTo) के साथ बदलें।
जोड़ा लेखक ToolmakerSteve, स्रोत

जिस तरह से मैं इसे करता हूं उसे एक स्ट्रक्चर बाधा डाल दी जाती है, फिर जांचें कि टी रनटाइम पर एक enum है। यह पूरी तरह से समस्या को खत्म नहीं करता है, लेकिन यह कुछ हद तक कम करता है

0
जोड़ा
जहां टी: संरचना, IComparable, IFormattable, IConvertible - यह सबसे निकट है आप enum पाने के लिए मिल सकता है :)
जोड़ा लेखक Kit, स्रोत

संपादित करें: यह अब UnconstrainedMelody के संस्करण 0.0.0.2 में लाइव है।

(जैसा कि मेरे enum के बारे में ब्लॉग पोस्ट पर अनुरोध किया गया है बाधाएं । मैंने स्टैंडअलोन उत्तर के लिए नीचे दिए गए मूल तथ्यों को शामिल किया है।)

सबसे अच्छा समाधान है कि मुझे इसे अनकॉन्स्ट्रेनडेलो 1 । यह एक पुस्तकालय है जो "नकली" बाधाओं के साथ सी # कोड लेता है

where T : struct, IEnumConstraint

और इसे बदल देता है

where T : struct, System.Enum

एक पोस्टबिल्ड चरण के माध्यम से।

IsSet लिखना बहुत कठिन नहीं होना चाहिए ... हालांकि Int64 -based और UInt64 -based झंडे दोनों के लिए खानपान मुश्किल हो सकता है अंश। (मैं कुछ सहायक तरीकों को गंध करता हूं, मूल रूप से मुझे किसी भी झंडे के साथ इलाज करने की इजाजत देता है जैसे कि इसका मूल प्रकार UInt64 था।)

यदि आप बुलाएंगे तो व्यवहार क्या होगा

tester.IsSet(MyFlags.A | MyFlags.C)

? क्या यह जांचना चाहिए कि निर्दिष्ट ध्वज सभी सेट हैं? यह मेरी उम्मीद होगी।

मैं आज रात घर पर ऐसा करने की कोशिश करूंगा ... मुझे आशा है कि लाइब्रेरी को उपयोग करने योग्य मानक तक जल्दी प्राप्त करने के लिए उपयोगी enum विधियों पर त्वरित ब्लिट्ज प्राप्त करने की उम्मीद है, फिर थोड़ा आराम करें।

संपादित करें: मुझे रास्ते में, IsSet के नाम के बारे में निश्चित नहीं है। विकल्प:

  • शामिल
  • शामिल
  • हैस्फ्लैग (या हैस्फ्लैग)
  • IsSet (यह निश्चित रूप से एक विकल्प है)

विचार स्वागत है। मुझे यकीन है कि पत्थर में किसी भी सेट के सेट से पहले कुछ समय लगेगा ...


1 or submit it as a patch, of course...

0
जोड़ा
मुझे लगता है कि अगर इसमें कई झंडे पास किए जाते हैं तो उन सभी की जांच करनी चाहिए। इसके लिए मेरा वास्तविक फिक्स (2008 में जब मैंने इसे पूछा था) प्रत्येक झंडे के लिए टेम्पलेट एक्सटेंशन विधि थी - गन्दा लेकिन काम करता है। कभी भी कई झंडे के लिए चेक से परेशान नहीं है क्योंकि हमारे पास सभी चेक एक ही ध्वज के लिए हैं - आंतरिक केवल कोड में ऐसी कोई समस्या नहीं है, लेकिन साझा लाइब्रेरी में कुछ ऐसा करने की आवश्यकता होगी।
जोड़ा लेखक Keith, स्रोत
या वास्तव में सरल हैस्नी() और HasAll ()
जोड़ा लेखक Keith, स्रोत
जैसे ही मैंने उत्तर के शीर्ष को पढ़ना शुरू किया, मैंने खुद को "एक और लाइब्रेरी" कहने लगे, जब तक कि यह जॉन स्कीट द्वारा लिखा गया न हो। " तब मैं नीचे स्क्रॉल किया, और पुरस्कृत किया गया था।
जोड़ा लेखक krillgar, स्रोत
आपको पोस्टशर्प एलओएल जाना और उल्लेख करना था: o postsharp.org/ ब्लॉग / सामान्य-बाधाओं के लिए enums और delegat और जेडडब्ल्यूएनजे; तों
जोड़ा लेखक Sam Harwell, स्रोत
कृपया शीर्ष पर लिंक अपडेट करें: enum बाधाओं के बारे में ब्लॉग पोस्ट
जोड़ा लेखक Zinov, स्रोत
हाँ, मुझे HasAny और HasAll भी पसंद है। उसके साथ चलेगा।
जोड़ा लेखक Jon Skeet, स्रोत
HasAny और HasAll भयानक लग रहा है।
जोड़ा लेखक IDisposable, स्रोत
हाँ, मैं मानता हूं कि यह भी बेहतर है। colors.HasAny (Colors.Red | Colors.Blue) बहुत पठनीय कोड की तरह दिखता है। =)
जोड़ा लेखक Blixt, स्रोत
ओह और कीथ, stackoverflow.com/questions/1404077/… =) में विशेष श्रेणी enum के सामान्य प्रकार की बाधा के लिए एक समाधान है
जोड़ा लेखक Blixt, स्रोत
मैं ध्वज-शब्दावली का उपयोग केवल इसलिए कर सकता हूं क्योंकि यह पहले से ही .NET में मौजूद है (देखें FlagsAttribute ।) मुझे यहां दो स्पष्ट नाम दिखाई देते हैं: HasAnyFlag और HasAllFlags । उन्हें HasFlag और HasFlags तक छोटा किया जा सकता है। मैं यह नहीं कह सकता कि कौन सा सबसे अच्छा है, यह मुझे लगता है कि स्वाद का मामला है।
जोड़ा लेखक Blixt, स्रोत

मैं सिर्फ एक सामान्य बाधा के रूप में Enum जोड़ना चाहता था।

हालांकि यह ExtraConstraints का उपयोग करके एक छोटी सहायक विधि के लिए है। मेरे लिए थोड़ा अधिक ओवरहेड।

मैंने बस एक struct बाधा उत्पन्न करने का निर्णय लिया और IsEnum के लिए रनटाइम चेक जोड़ें। टी से एनम तक एक चर बदलने के लिए मैंने इसे पहले ऑब्जेक्ट करने के लिए डाला।

    public static Converter CreateConverter() where T : struct
    {
        if (!typeof(T).IsEnum) throw new ArgumentException("Given Type is not an Enum");
        return new Converter(x => ((Enum)(object)x).GetEnumDescription());
    }
0
जोड़ा

You can achieve this using IL Weaving and ExtraConstraints

आपको यह कोड लिखने की अनुमति देता है

public class Sample
{
    public void MethodWithDelegateConstraint<[DelegateConstraint] T> ()
    {        
    }
    public void MethodWithEnumConstraint<[EnumConstraint] T>()
    {
    }
}

संकलित हो जाता है

public class Sample
{
    public void MethodWithDelegateConstraint() where T: Delegate
    {
    }

    public void MethodWithEnumConstraint() where T: struct, Enum
    {
    }
}
0
जोड़ा

दरअसल, एक बदसूरत चाल के साथ, यह संभव है। हालांकि, इसका उपयोग विस्तार विधियों के लिए नहीं किया जा सकता है।

public abstract class Enums where Temp : class {
    public static TEnum Parse(string name) where TEnum : struct, Temp {
        return (TEnum)Enum.Parse(typeof(TEnum), name); 
    }
}
public abstract class Enums : Enums { }

Enums.IsSet("Local")

If you want to, you can give Enums a private constructor and a public nested abstract inherited class with Temp as Enum, to prevent inherited versions for non-enums.

0
जोड़ा

विधि के अंदर, अपने मूल कोड का उपयोग करके आप यह जांचने के लिए प्रतिबिंब का उपयोग भी कर सकते हैं कि टी एक enum है:

public static class EnumExtension
{
    public static bool IsSet( this T input, T matchTo )
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("Must be an enum", "input");
        }
        return (input & matchTo) != 0;
    }
}
0
जोड़ा
धन्यवाद, लेकिन यह रनटाइम एक (आपके अपवाद) में संकलन समय समस्या (जहां बाधा) बदल जाता है। इससे पहले कि आप उनके साथ कुछ भी कर सकें, आपको इनपुट को इनट्स में कनवर्ट करने की आवश्यकता होगी।
जोड़ा लेखक Keith, स्रोत

यह मूल प्रश्न का उत्तर नहीं देता है, लेकिन अब .NET 4 में एक विधि है जिसे Enum.HasFlag जो आप अपने उदाहरण में करने की कोशिश कर रहे हैं

0
जोड़ा
Upvoted। हालांकि उनका समाधान तर्क ध्वज के मुक्केबाजी का उपयोग करता है। .NET 4.0 अब पांच साल का है।
जोड़ा लेखक Jeppe Stig Nielsen, स्रोत
उपरोक्त क्योंकि इस बिंदु पर, अधिकांश को .NET 4 (या उच्चतर) का उपयोग करना चाहिए और इसलिए उन्हें एक साथ हैक करने की कोशिश करने के बजाय इस विधि का उपयोग करना चाहिए।
जोड़ा लेखक CptRobby, स्रोत

यहां कुछ कोड है जो मैंने अभी किया है जो ऐसा लगता है जैसे आप कुछ भी पागल होने के बिना चाहते हैं। यह केवल ध्वज के रूप में सेट किए गए enums तक ही सीमित नहीं है, लेकिन आवश्यकता होने पर हमेशा एक चेक लगाया जा सकता है।

public static class EnumExtensions
{
    public static bool ContainsFlag(this Enum source, Enum flag)
    {
        var sourceValue = ToUInt64(source);
        var flagValue = ToUInt64(flag);

        return (sourceValue & flagValue) == flagValue;
    }

    public static bool ContainsAnyFlag(this Enum source, params Enum[] flags)
    {
        var sourceValue = ToUInt64(source);

        foreach (var flag in flags)
        {
            var flagValue = ToUInt64(flag);

            if ((sourceValue & flagValue) == flagValue)
            {
                return true;
            }
        }

        return false;
    }

    // found in the Enum class as an internal method
    private static ulong ToUInt64(object value)
    {
        switch (Convert.GetTypeCode(value))
        {
            case TypeCode.SByte:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
                return (ulong)Convert.ToInt64(value, CultureInfo.InvariantCulture);

            case TypeCode.Byte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
                return Convert.ToUInt64(value, CultureInfo.InvariantCulture);
        }

        throw new InvalidOperationException("Unknown enum type.");
    }
}
0
जोड़ा

अगर किसी को सामान्य आईएससेट (फ्लाई पर बॉक्स से बाहर बनाया गया) में सुधार किया जा सकता है, और एनम ऑनफ्लाई रूपांतरण (जो नीचे प्रस्तुत EnumConstraint का उपयोग करता है) की स्ट्रिंग की आवश्यकता है:

  public class TestClass
  { }

  public struct TestStruct
  { }

  public enum TestEnum
  {
    e1,    
    e2,
    e3
  }

  public static class TestEnumConstraintExtenssion
  {

    public static bool IsSet(this TEnum _this, TEnum flag)
      where TEnum : struct
    {
      return (((uint)Convert.ChangeType(_this, typeof(uint))) & ((uint)Convert.ChangeType(flag, typeof(uint)))) == ((uint)Convert.ChangeType(flag, typeof(uint)));
    }

    //public static TestClass ToTestClass(this string _this)
    //{
    //  // #generates compile error  (so no missuse)
    //  return EnumConstraint.TryParse(_this);
    //}

    //public static TestStruct ToTestStruct(this string _this)
    //{
    //  // #generates compile error  (so no missuse)
    //  return EnumConstraint.TryParse(_this);
    //}

    public static TestEnum ToTestEnum(this string _this)
    {
      // #enum type works just fine (coding constraint to Enum type)
      return EnumConstraint.TryParse(_this);
    }

    public static void TestAll()
    {
      TestEnum t1 = "e3".ToTestEnum();
      TestEnum t2 = "e2".ToTestEnum();
      TestEnum t3 = "non existing".ToTestEnum(); // default(TestEnum) for non existing 

      bool b1 = t3.IsSet(TestEnum.e1); // you can ommit type
      bool b2 = t3.IsSet(TestEnum.e2); // you can specify explicite type

      TestStruct t;
      // #generates compile error (so no missuse)
      //bool b3 = t.IsSet(TestEnum.e1);

    }

  }

अगर किसी को अभी भी एनम कोडिंग बाधा बनाने के लिए गर्म उदाहरण की आवश्यकता है:

using System;

/// 
/// would be same as EnumConstraint_T<Enum>Parse<EnumType>("Normal"), /// but writen like this it abuses constrain inheritence on System.Enum. ///
 
public class EnumConstraint : EnumConstraint_T
{

}

/// 
/// provides ability to constrain TEnum to System.Enum abusing constrain inheritence ///
 
/// should be System.Enum
public abstract class EnumConstraint_T
  where TClass : class
{

  public static TEnum Parse(string value)
    where TEnum : TClass
  {
    return (TEnum)Enum.Parse(typeof(TEnum), value);
  }

  public static bool TryParse(string value, out TEnum evalue)
    where TEnum : struct, TClass // struct is required to ignore non nullable type error
  {
    evalue = default(TEnum);
    return Enum.TryParse(value, out evalue);
  }

  public static TEnum TryParse(string value, TEnum defaultValue = default(TEnum))
    where TEnum : struct, TClass // struct is required to ignore non nullable type error
  {    
    Enum.TryParse(value, out defaultValue);
    return defaultValue;
  }

  public static TEnum Parse(string value, TEnum defaultValue = default(TEnum))
    where TEnum : struct, TClass // struct is required to ignore non nullable type error
  {
    TEnum result;
    if (Enum.TryParse(value, out result))
      return result;
    return defaultValue;
  }

  public static TEnum Parse(ushort value)
  {
    return (TEnum)(object)value;
  }

  public static sbyte to_i1(TEnum value)
  {
    return (sbyte)(object)Convert.ChangeType(value, typeof(sbyte));
  }

  public static byte to_u1(TEnum value)
  {
    return (byte)(object)Convert.ChangeType(value, typeof(byte));
  }

  public static short to_i2(TEnum value)
  {
    return (short)(object)Convert.ChangeType(value, typeof(short));
  }

  public static ushort to_u2(TEnum value)
  {
    return (ushort)(object)Convert.ChangeType(value, typeof(ushort));
  }

  public static int to_i4(TEnum value)
  {
    return (int)(object)Convert.ChangeType(value, typeof(int));
  }

  public static uint to_u4(TEnum value)
  {
    return (uint)(object)Convert.ChangeType(value, typeof(uint));
  }

}

उम्मीद है कि यह किसी की मदद करता है।

0
जोड़ा

सी # 7.3 के रूप में, अब enum बाधाओं को जोड़ने के लिए एक अंतर्निहित तरीका है:

public class UsingEnum where T : System.Enum { }

source: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint

0
जोड़ा