কোনও পতাকা সংমিশ্রনের কোনও পতাকা সেট করা আছে কিনা তা কীভাবে পরীক্ষা করবেন?


180

ধরা যাক আমার এই এনাম আছে:

[Flags]
enum Letters
{
     A = 1,
     B = 2,
     C = 4,
     AB = A | B,
     All = A | B | C,
}

উদাহরণস্বরূপ ABসেট করা আছে কিনা তা পরীক্ষা করতে আমি এটি করতে পারি:

if((letter & Letters.AB) == Letters.AB)

সম্মিলিত পতাকা ধ্রুবকের কোনও পতাকা নীচের চেয়ে সেট করা আছে কিনা তা যাচাই করার সহজ উপায় আছে কি?

if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B)

আপনি উদাহরণস্বরূপ &কিছু দিয়ে অদলবদল করতে পারেন?

এটি যখন বাইনারি স্টাফ আসে তখন খুব স্থিতিশীল নয় ...


সকলকে 'All = A | পড়া উচিত নয় খ | সি '?
স্টিভিহওয়েল

4
এবি | সি এর সমতুল্য | খ | সি কারণ এবি সংজ্ঞা ছিল A | এর আগে বি।
ড্যানিয়েল ব্রুকনার

1
@ ড্যানিয়েল ব্রুকনার - এটি সমান, তবে এটি কম পাঠযোগ্য। বিশেষত যদি এনামটি প্রসারিত করা হত।
স্টিভিপওয়েল

সত্য। আমি আরও ভাল পড়ার জন্য এটি পরিবর্তন করতে পারেন।
সভিশ

উত্তর:


145

আপনি যদি জানতে চান যে AB এ অক্ষরটির কোনও চিঠি রয়েছে কিনা আপনাকে অবশ্যই AND এবং অপারেটরটি ব্যবহার করতে হবে । কিছুটা এইরকম:

if ((letter & Letters.AB) != 0)
{
    // Some flag (A,B or both) is enabled
}
else
{
    // None of them are enabled
}

2
আমি যতদূর দেখতে পাচ্ছি, এটি কাজ করে। এবং পরিষ্কার মন্তব্য ছিল। চারপাশে প্রথম বন্ধনী ছাড়া সঙ্কলন করে না letter & Letters.AB। সেখানে সম্পাদিত।
Svish

এছাড়াও আমি যদি একটি পরিচয় করিয়ে দিয়েছি Letters.None, আমি ধরে নিচ্ছি যে আপনি 0যাদু-সংখ্যার তুলনায় কম তুলনা করার জন্য এটির সাথে অদলবদল করতে পারেন?
সুইভিশ

অবশ্যই. তবে আমি মনে করি না যে 0 এর সাথে এবং এর তুলনা কঠোরভাবে একটি যাদু সংখ্যা হিসাবে ভাবা যেতে পারে।
ইয়েইয়েরম্যান

9
এছাড়াও স্ট্যাকওভারফ্লো / সেকশনস / 40211/how-to-compare-flags- in- c একটি প্রস্তাবিত উত্তর কারণ এটি আইনের বিপরীতে যা 0
ড্যান রিচার্ডসন

@ উদ্যানচর্দসন সঠিক আইটেমটি যাচাইয়ের ক্ষেত্রে সমস্যাটি হ'ল যৌগিক মানটির একটি অংশ (এ, বা বি) সেট করা হলে এটি কেসটি সরিয়ে দেয় , যা ওপি চায় না।
টম লিন্ট

181

.NET 4 এ আপনি Enum.HasFlag পদ্ধতিটি ব্যবহার করতে পারেন :

using System;

[Flags] public enum Pet {
   None = 0,
   Dog = 1,
   Cat = 2,
   Bird = 4,
   Rabbit = 8,
   Other = 16
}

public class Example
{
   public static void Main()
   {
      // Define three families: one without pets, one with dog + cat and one with a dog only
      Pet[] petsInFamilies = { Pet.None, Pet.Dog | Pet.Cat, Pet.Dog };
      int familiesWithoutPets = 0;
      int familiesWithDog = 0;

      foreach (Pet petsInFamily in petsInFamilies)
      {
         // Count families that have no pets. 
         if (petsInFamily.Equals(Pet.None))
            familiesWithoutPets++;
         // Of families with pets, count families that have a dog. 
         else if (petsInFamily.HasFlag(Pet.Dog))
            familiesWithDog++;
      }
      Console.WriteLine("{0} of {1} families in the sample have no pets.", 
                        familiesWithoutPets, petsInFamilies.Length);   
      Console.WriteLine("{0} of {1} families in the sample have a dog.", 
                        familiesWithDog, petsInFamilies.Length);   
   }
}

উদাহরণটি নিম্নলিখিত আউটপুট প্রদর্শন করে:

//       1 of 3 families in the sample have no pets. 
//       2 of 3 families in the sample have a dog.

14
এটি ওপি প্রশ্নের সমাধান করে না। কোনও পতাকা সেট আছে কিনা তা নির্ধারণ করতে আপনাকে অবশ্যই && একাধিক হাসফ্ল্যাগ অপারেশন করতে হবে । সুতরাং প্রশ্ন petsInFamilyএকটি হয় না Pet.Dog || Pet.Cat?
GoClimbColorado


59

আমি এ জাতীয় জিনিস লিখতে এক্সটেনশন পদ্ধতি ব্যবহার করি:

if (letter.IsFlagSet(Letter.AB))
    ...

কোডটি এখানে:

public static class EnumExtensions
{
    private static void CheckIsEnum<T>(bool withFlags)
    {
        if (!typeof(T).IsEnum)
            throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName));
        if (withFlags && !Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)))
            throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName));
    }

    public static bool IsFlagSet<T>(this T value, T flag) where T : struct
    {
        CheckIsEnum<T>(true);
        long lValue = Convert.ToInt64(value);
        long lFlag = Convert.ToInt64(flag);
        return (lValue & lFlag) != 0;
    }

    public static IEnumerable<T> GetFlags<T>(this T value) where T : struct
    {
        CheckIsEnum<T>(true);
        foreach (T flag in Enum.GetValues(typeof(T)).Cast<T>())
        {
            if (value.IsFlagSet(flag))
                yield return flag;
        }
    }

    public static T SetFlags<T>(this T value, T flags, bool on) where T : struct
    {
        CheckIsEnum<T>(true);
        long lValue = Convert.ToInt64(value);
        long lFlag = Convert.ToInt64(flags);
        if (on)
        {
            lValue |= lFlag;
        }
        else
        {
            lValue &= (~lFlag);
        }
        return (T)Enum.ToObject(typeof(T), lValue);
    }

    public static T SetFlags<T>(this T value, T flags) where T : struct
    {
        return value.SetFlags(flags, true);
    }

    public static T ClearFlags<T>(this T value, T flags) where T : struct
    {
        return value.SetFlags(flags, false);
    }

    public static T CombineFlags<T>(this IEnumerable<T> flags) where T : struct
    {
        CheckIsEnum<T>(true);
        long lValue = 0;
        foreach (T flag in flags)
        {
            long lFlag = Convert.ToInt64(flag);
            lValue |= lFlag;
        }
        return (T)Enum.ToObject(typeof(T), lValue);
    }

    public static string GetDescription<T>(this T value) where T : struct
    {
        CheckIsEnum<T>(false);
        string name = Enum.GetName(typeof(T), value);
        if (name != null)
        {
            FieldInfo field = typeof(T).GetField(name);
            if (field != null)
            {
                DescriptionAttribute attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
                if (attr != null)
                {
                    return attr.Description;
                }
            }
        }
        return null;
    }
}

1
আপনি এটি একটি তাই মত কঠিন বিট করতে পারে: where T : struct, IConvertible। অন্যথায় দুর্দান্ত কোড!
হামিশ গ্রুবিজন

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

ভাগ করে নেওয়ার জন্য ধন্যবাদ তবে আপনাকে সর্বদা এনাম পরীক্ষা করার দরকার নেই। IsFlagSet(this Enum value, Enum flag)পর্যাপ্ত.
djmj

34

নেই HasFlag .NET 4 বা উচ্চতর মধ্যে পদ্ধতি।

if(letter.HasFlag(Letters.AB))
{
}

26

যদি আপনি .NET 4 বা তার চেয়ে বেশি ব্যবহার করতে পারেন তবে hasFlag () পদ্ধতি ব্যবহার করুন

উদাহরণ

letter.HasFlag(Letters.A | Letters.B) // both A and B must be set

একই রকম

letter.HasFlag(Letters.AB)

আপনি কি নিশ্চিত যে bitwise ORএটি "উভয়ই সেট করা উচিত" এবং কোনওটি নয়?
বন্ধনী

1
bitwise ORমানগুলি একত্রিত করবে, তাই 1000 | 0010 1010 হয়ে, অথবা উভয় সেট
আর্মন্দ

13

যদি এটি আপনাকে সত্যই বিরক্ত করে, আপনি এর মতো একটি ফাংশন লিখতে পারেন:

public bool IsSet(Letters value, Letters flag)
{
    return (value & flag) == flag;
}

if (IsSet(letter, Letters.A))
{
   // ...
}

// If you want to check if BOTH Letters.A and Letters.B are set:
if (IsSet(letter, Letters.A & Letters.B))
{
   // ...
}

// If you want an OR, I'm afraid you will have to be more verbose:
if (IsSet(letter, Letters.A) || IsSet(letter, Letters.B))
{
   // ...
}

1
লাইনটি return (value & flag) == flag;সংকলন করে না: "অপারেটর 'এবং' টি 'এবং' টি 'টাইপের অপারেন্ডগুলিতে প্রয়োগ করা যায় না
ফ্রেডরিক মের্ক

1
বিস্ময়: প্রশ্নটি বাইনারি অপারেশন সম্পর্কে নয়, প্রশ্নটি সি # তে বিটমাস্ক-সম্পর্কিত অপারেশনগুলির সিনট্যাক্সকে সহজ করার বিষয়ে ছিল। ইতিমধ্যে স্ট্যাকওভারফ্লোতে প্রচুর চমৎকার বাইনারি অপারেশন সম্পর্কিত প্রশ্ন এবং উত্তর রয়েছে, এগুলি সর্বত্র পুনরায় পোস্ট করার দরকার নেই।
তামাস কেজিঞ্জে

আমার সুপারিশ করা উচিত যে বাইনারি অপারেশনগুলির সাথে অপরিচিত যারা পরিচিত হন, কারণ এটি উপরে লুকিয়ে রাখার ভারাটি আমার মতে জিনিসগুলিকে অনেক কম পাঠযোগ্য করে তোলে। অবশ্যই নীচের আমার 'কাঁচা' সমাধানটি বর্তমানে এই সমাধানের স্কোরের তুলনায় খুব ভাল করছে না, তাই লোকেরা তাদের পছন্দকে ভোট দিচ্ছে এবং আমাকে এই সম্মান জানাতে হবে ;-)
উইল

10

উদাহরণস্বরূপ AB সেট করা আছে কিনা তা পরীক্ষা করতে আমি এটি করতে পারি:

if ((চিঠি এবং চিঠিগুলি .AB) == লেটার.এবি)

সম্মিলিত পতাকা ধ্রুবকের কোনও পতাকা নীচের চেয়ে সেট করা আছে কিনা তা যাচাই করার সহজ উপায় আছে কি?

এটি এবং বি উভয় সেট করা আছে কিনা তা পরীক্ষা করে এবং অন্য কোনও পতাকা সেট করা আছে কিনা তা উপেক্ষা করে।

if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B)

এই চেক যে পারেন A অথবা B সেট করা হয় এবং উপেক্ষা অন্য কোন পতাকা বা নির্ধারণ করা হয় কি না।

এটি সরল করা যেতে পারে:

if(letter & Letters.AB)

বাইনারি অপারেশনগুলির জন্য এখানে সি; এটি সি # তে প্রয়োগ করা সহজবোধ্য হওয়া উচিত:

enum {
     A = 1,
     B = 2,
     C = 4,
     AB = A | B,
     All = AB | C,
};

int flags = A|C;

bool anything_and_a = flags & A;

bool only_a = (flags == A);

bool a_and_or_c_and_anything_else = flags & (A|C);

bool both_ac_and_anything_else = (flags & (A|C)) == (A|C);

bool only_a_and_c = (flags == (A|C));

ঘটনাক্রমে, প্রশ্নের উদাহরণে পরিবর্তনশীলটির নামকরণ একক 'অক্ষর', যা বোঝাতে পারে যে এটি কেবলমাত্র একটি অক্ষরকে উপস্থাপন করে; উদাহরণ কোডটি এটি পরিষ্কার করে দেয় যে এটি সম্ভাব্য অক্ষরের একটি সেট এবং একাধিক মান অনুমোদিত, সুতরাং ভেরিয়েবলের 'অক্ষর' নামকরণের বিষয়টি বিবেচনা করুন।


করবে না anything_and_a, a_and_or_c_and_anything_elseএবং both_ac_and_anything_elseসবসময় সত্য হতে পারে? বা আমি এখানে কিছু মিস করছি?
সুইভিশ

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

হুঁ, এর মধ্যে কয়েকটি সংখ্যা হিসাবে শেষ হয়েছে এবং যদিও সি # তে বুলিয়ান নয়। আপনি কীভাবে এগুলিকে বুলেয়ানে রূপান্তর করবেন?
Svish

এটি আপনার জন্য স্পষ্টত রূপান্তরিত হয় না? শূন্যটি 'মিথ্যা' সমতুল্য এবং অন্যান্য সমস্ত মান 'সত্য'।
উইল

4

কেমন

if ((letter & Letters.AB) > 0)

?


হ্যাঁ! এটি A এবং B মানগুলিতে ফিল্টার করবে এবং সি অন্তর্ভুক্ত করা থাকলে তা উপেক্ষা করবে। সুতরাং এটি যদি 0 হয় তবে এটি A বা B বা ABও হয়।
অবাক

3
এটি স্বাক্ষরিত মানগুলির সাথে 100% কাজ করে না। ! = 0 এই কারণে> 0 এর চেয়ে ভাল।
স্টিভিহওয়েল

4

আমি একটি সাধারণ এক্সটেনশন পদ্ধতি তৈরি করেছি যার Enumপ্রকারভেদে কোনও চেকের দরকার নেই :

public static bool HasAnyFlag(this Enum value, Enum flags)
{
    return
        value != null && ((Convert.ToInt32(value) & Convert.ToInt32(flags)) != 0);
}

এটি অযোগ্য এনামগুলিতেও কাজ করে। মানক HasFlagপদ্ধতিটি হ'ল না, তাই এটিও কভার করতে আমি একটি এক্সটেনশন তৈরি করেছি।

public static bool HasFlag(this Enum value, Enum flags)
{
    int f = Convert.ToInt32(flags);

    return
        value != null && ((Convert.ToInt32(value) & f) == f);
}

একটি সহজ পরীক্ষা:

[Flags]
enum Option
{
    None = 0x00,
    One = 0x01,
    Two = 0x02,
    Three = One | Two,
    Four = 0x04
}

[TestMethod]
public void HasAnyFlag()
{
    Option o1 = Option.One;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(false, o1.HasFlag(Option.Three));

    o1 |= Option.Two;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(true, o1.HasFlag(Option.Three));
}

[TestMethod]
public void HasAnyFlag_NullableEnum()
{
    Option? o1 = Option.One;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(false, o1.HasFlag(Option.Three));

    o1 |= Option.Two;
    Assert.AreEqual(true, o1.HasAnyFlag(Option.Three));
    Assert.AreEqual(true, o1.HasFlag(Option.Three));
}

উপভোগ করুন!


4

এখানে অনেক উত্তর রয়েছে তবে আমি মনে করি পতাকাগুলির সাথে এটি করার সবচেয়ে মূর্খ উপায় হ'ল লেটারস.এ.বি.হ্যাসফ্ল্যাগ (চিঠি) বা (চিঠিগুলি। এ। লেটারস.বি) ।হাসফ্ল্যাগ (চিঠি) যদি আপনি না করেন তবে ইতিমধ্যে Letters.AB রয়েছে। লেটার.হ্যাসফ্লেগ (লেটারস.এবি) কেবলমাত্র যদি এটি উভয়ই থাকে তবে কাজ করে।



1

আপনি এনামে এই প্রসারণ পদ্ধতিটি যে কোনও প্রকারের এনামের জন্য ব্যবহার করতে পারেন:

public static bool IsSingle(this Enum value)
{
    var items = Enum.GetValues(value.GetType());
    var counter = 0;
    foreach (var item in items)
    {
        if (value.HasFlag((Enum)item))
        {
            counter++;
        }
        if (counter > 1)
        {
            return false;
        }
    }
    return true;
}

0
if((int)letter != 0) { }

আপনিও আমার মতো ভুলটি করতে পারেন - তিনি এ বা বি সেট হয়েছে কিনা তা যাচাই করতে চান তবে সি উপেক্ষা করুন
ড্যানিয়েল ব্রুকনার

আপনি যদি 0. এর বিপরীতে
এনাম

এটি যাচাই করে যে এগুলির মধ্যে কোনও একটি সেট করা আছে কিনা, সম্মিলিত এনামের কোনও সেট করা হয়নি কিনা।
সুইভিশ

0

মানটি শূন্য নয় কিনা আপনি কেবল তা পরীক্ষা করতে পারেন।

if ((Int32)(letter & Letters.AB) != 0) { }

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

[Flags]
enum Letters
{
    None = 0,
    A    = 1,
    B    = 2,
    C    = 4,
    AB   =  A | B,
    All  = AB | C
}

if (letter != Letters.None) { }

হালনাগাদ

প্রশ্নটি মিস করুন - প্রথম পরামর্শটি স্থির করুন এবং দ্বিতীয় পরামর্শটি উপেক্ষা করুন।


আপনি যদি 0. এর বিপরীতে
এনাম

0

দুটি অ্যাপ্রোচ রয়েছে যা আমি দেখতে পাচ্ছি যে কোনও বিট সেট হওয়ার জন্য এটি পরীক্ষা করার জন্য কাজ করবে।

অ্যাপ্রোচ এ

if (letter != 0)
{
}

এটি ততক্ষণ কাজ করে যতক্ষণ না আপনি সকলের জন্য যাচাই করতে আপত্তি করেন না বিটগুলির , অ-সংজ্ঞায়িতগুলিও সহ!

অ্যাপ্রোচ বি

if ((letter & Letters.All) != 0)
{
}

এটি কেবলমাত্র যতক্ষণ লেটারস হিসাবে সমস্ত সংজ্ঞায়িত বিটকে উপস্থাপন করে ততক্ষণ সংজ্ঞায়িত বিটগুলি পরীক্ষা করে।

নির্দিষ্ট বিটগুলির জন্য (এক বা একাধিক সেট), চিঠিগুলি প্রতিস্থাপনের জন্য অ্যাপ্রোচ বি ব্যবহার করুন you আপনি যে বিটগুলি পরীক্ষা করতে চান তা দিয়ে (নীচে দেখুন)।

if ((letter & Letters.AB) != 0)
{
}

আপনিও আমার মতো ভুলটি করতে পারেন - তিনি এ বা বি সেট হয়েছে কিনা তা যাচাই করতে চান তবে সি উপেক্ষা করুন
ড্যানিয়েল ব্রুকনার

-1

দুঃখিত, তবে আমি এটি ভিবিতে দেখাবো :)

   <Flags()> Public Enum Cnt As Integer
        None = 0
        One = 1
        Two = 2
        Three = 4
        Four = 8    
    End Enum

    Sub Test()
    Dim CntValue As New Cnt
    CntValue += Cnt.One
    CntValue += Cnt.Three
    Console.WriteLine(CntValue)
    End Sub

CntValue = 5 সুতরাং এনামে 1 + 4 রয়েছে

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