এনামগুলিতে সর্বাধিক সাধারণ সি # বিটওয়াইজ অপারেশন


201

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

উদাহরণ স্বরূপ:

flags = flags | FlagsEnum.Bit4;  // Set bit 4.

অথবা

if ((flags & FlagsEnum.Bit4)) == FlagsEnum.Bit4) // Is there a less verbose way?

আপনি [ফ্ল্যাগস] এনাম ব্যবহার করে সি # সিনট্যাক্সে অন্যান্য সমস্ত সাধারণ ক্রিয়াকলাপের উদাহরণ দিতে পারেন?



7
খুব খারাপ যে লিঙ্কটি এই বিষয়ের জন্য প্রশ্ন ইঙ্গিতগুলিতে উপস্থিত হয় না।
করি

10
এই প্রশ্নটি সি / সি ++ এর জন্য ট্যাগ করা আছে, যদিও সি # সম্পর্কিত তথ্য অনুসন্ধান করছে এমন কেউ হয়ত বাক্য গঠনটি একইরকম দেখা দিলেও সেখানে দেখতে পাবেন না।
অ্যাডাম লাসেক 16

আমি বিট পরীক্ষা করার জন্য কোনও কম ভার্বোজ উপায় সম্পর্কে অবগত নই
অ্যান্ডি জনসন

2
@ অ্যান্ডি, নেট নেট 4 এ বিট পরীক্ষার জন্য একটি এপিআই রয়েছে।
ড্রয় নোকস

উত্তর:


288

আমি এই এক্সটেনশনগুলিতে আরও কিছু কাজ করেছি - আপনি কোডটি এখানে খুঁজে পেতে পারেন

আমি কিছু এক্সটেনশন পদ্ধতি লিখেছিলাম যা আমি প্রায়শই ব্যবহার করি এমন System.Enum প্রসারিত করে ... আমি দাবি করছি না যে এগুলি বুলেটপ্রুফ, তবে তারা সহায়তা করেছে ... মন্তব্যগুলি সরানো হয়েছে ...

namespace Enum.Extensions {

    public static class EnumerationExtensions {

        public static bool Has<T>(this System.Enum type, T value) {
            try {
                return (((int)(object)type & (int)(object)value) == (int)(object)value);
            } 
            catch {
                return false;
            }
        }

        public static bool Is<T>(this System.Enum type, T value) {
            try {
                return (int)(object)type == (int)(object)value;
            }
            catch {
                return false;
            }    
        }


        public static T Add<T>(this System.Enum type, T value) {
            try {
                return (T)(object)(((int)(object)type | (int)(object)value));
            }
            catch(Exception ex) {
                throw new ArgumentException(
                    string.Format(
                        "Could not append value from enumerated type '{0}'.",
                        typeof(T).Name
                        ), ex);
            }    
        }


        public static T Remove<T>(this System.Enum type, T value) {
            try {
                return (T)(object)(((int)(object)type & ~(int)(object)value));
            }
            catch (Exception ex) {
                throw new ArgumentException(
                    string.Format(
                        "Could not remove value from enumerated type '{0}'.",
                        typeof(T).Name
                        ), ex);
            }  
        }

    }
}

তারপরে সেগুলি নীচের মত ব্যবহার করা হয়

SomeType value = SomeType.Grapes;
bool isGrapes = value.Is(SomeType.Grapes); //true
bool hasGrapes = value.Has(SomeType.Grapes); //true

value = value.Add(SomeType.Oranges);
value = value.Add(SomeType.Apples);
value = value.Remove(SomeType.Grapes);

bool hasOranges = value.Has(SomeType.Oranges); //true
bool isApples = value.Is(SomeType.Apples); //false
bool hasGrapes = value.Has(SomeType.Grapes); //false

1
আমি এটি দরকারীও পেয়েছি - কোনও ধারণা কীভাবে আমি এটিকে সংশোধন করতে পারি যাতে এটি কোনও অন্তর্নিহিত ধরণের উপর কাজ করে?
চার্লি সল্টস

7
এই এক্সটেনশানগুলি সবেমাত্র আমার দিন, আমার সপ্তাহ, আমার মাস এবং সম্ভবত আমার বছর তৈরি করেছে।
thaBadDawg

ধন্যবাদ! প্রত্যেকে: হুগোয়ারের সাথে আপডেট হওয়া আপডেটটি পরীক্ষা করে দেখুন।
হেল্জ করুন

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

4
@ ড্রু: বক্সিং এড়ানোর উপায়ের জন্য কোড. google.com/p/unconstrained- মেলোডি দেখুন :)
জন স্কিপ

109

নেট 4 এ আপনি এখন লিখতে পারেন:

flags.HasFlag(FlagsEnum.Bit4)

4
এটি উল্লেখ করার জন্য +1, যদিও FlagsEnumএটি একটি কুৎসিত নাম। :)
জিম শুবার্ট

2
@ জিম, সম্ভবত এটি কেবলমাত্র একটি নমুনার নাম, মূল প্রশ্নে ব্যবহৃত হিসাবে এটি আপনার কোডটিতে এটি পরিবর্তন করতে মুক্ত।
ড্র নোকস

14
আমি জানি! তবে কুৎসিত নামগুলি আইআই 6 এর মতো এবং সম্ভবত কখনই দূরে যাবে না :(
জিম শোবার্ট

5
@ জিমস্কুবার্ট আবার, আমি মূল প্রশ্নটি থেকে প্রকারের নামটি পুনঃপ্রবর্তন করেছি যাতে বিষয়টি বিভ্রান্ত না হয়। .NET পরিগণনা প্রকার নামকরণ নির্দেশিকা নির্দেশ করে যে সব [Flags]enums pluralised নাম, তাই নাম থাকা উচিত FlagsEnumকদর্যতা চেয়ে আরও বেশি গুরুতর বিষয় আছে।
ড্রয় নোকস

1
আমি ফ্রেমওয়ার্ক ডিজাইনের গাইডলাইনগুলি: পুনরায় ব্যবহারযোগ্য। নেট গ্রন্থাগারগুলির জন্য কনভেনশন, আইডিয়াম এবং প্যাটার্নগুলিরও প্রস্তাব দিই । এটি কিনতে কিছুটা ব্যয়বহুল, তবে আমি বিশ্বাস করি সাফারি অনলাইন এবং বুকস 24x7 উভয়ই এটি গ্রাহকদের জন্য অফার করে।
জিম শুবার্ট

89

বিড়ালটি সেট করতে বিটওয়াইস বা সমমানের অপারেটরটি হ'ল প্রতিমাটি:

flags |= 0x04;

কিছুটা সাফ করার জন্য, আইডিয়ামটি হ'ল বিটওয়াইজ এবং অবহেলা সহ:

flags &= ~0x04;

কখনও কখনও আপনার একটি অফসেট থাকে যা আপনার বিটটিকে চিহ্নিত করে এবং তারপরে এই প্রতিমাটি বাম-শিফটের সাথে মিলিতভাবে ব্যবহার করতে হয়:

flags |= 1 << offset;
flags &= ~(1 << offset);

22

@Drew

মনে রাখবেন যে সহজতম ক্ষেত্রে ব্যতীত এনাম.হ্যাসফ্ল্যাগ ম্যানুয়ালি কোড লেখার তুলনায় ভারী পারফরম্যান্সের জরিমানা বহন করে। নিম্নলিখিত কোড বিবেচনা করুন:

[Flags]
public enum TestFlags
{
    One = 1,
    Two = 2,
    Three = 4,
    Four = 8,
    Five = 16,
    Six = 32,
    Seven = 64,
    Eight = 128,
    Nine = 256,
    Ten = 512
}


class Program
{
    static void Main(string[] args)
    {
        TestFlags f = TestFlags.Five; /* or any other enum */
        bool result = false;

        Stopwatch s = Stopwatch.StartNew();
        for (int i = 0; i < 10000000; i++)
        {
            result |= f.HasFlag(TestFlags.Three);
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *4793 ms*

        s.Restart();
        for (int i = 0; i < 10000000; i++)
        {
            result |= (f & TestFlags.Three) != 0;
        }
        s.Stop();
        Console.WriteLine(s.ElapsedMilliseconds); // *27 ms*        

        Console.ReadLine();
    }
}

10 মিলিয়নেরও বেশি পুনরাবৃত্তির সাথে, স্ট্যান্ডার্ড বিটওয়াইজ বাস্তবায়নের জন্য 27 এমএসের তুলনায়, হ্যাশফ্লাগস এক্সটেনশান পদ্ধতিটি পুরোপুরি 4793 এমএস নেয়।


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

7
HasFlagপদ্ধতি বক্সিং / আনবক্সিং জড়িত থাকে, যা এই পার্থক্য জন্য অ্যাকাউন্ট। তবে ব্যয়টি এত তুচ্ছ (0.4µs) যে আপনি যদি কোনও টান লুপ না করে থাকেন তবে আমি যে কোনও দিন আরও বেশি পঠনযোগ্য (এবং কম বগী) ডিক্লারেটিভাল এপিআই কলটি নেব।
ড্রয় নোকস

8
ব্যবহারের উপর নির্ভর করে এটি কোনও সমস্যা হতে পারে। এবং যেহেতু আমি লোডারগুলির সাথে বেশ খানিকটা কাজ করি, আমি বুঝতে পেরেছিলাম যে এটি উল্লেখ করা ভাল।
চক ডি

11

.NET এর অন্তর্নির্মিত ফ্ল্যাগ এনাম অপারেশন দুর্ভাগ্যক্রমে যথেষ্ট সীমাবদ্ধ। বেশিরভাগ সময় ব্যবহারকারীরা বিটওয়াইজ অপারেশন যুক্তি খুঁজে বের করতে পারেন।

.NET 4-এ, পদ্ধতিটি HasFlagযুক্ত করা হয়েছিল Enumযা ব্যবহারকারীর কোড সহজীকরণে সহায়তা করে তবে দুর্ভাগ্যক্রমে এর সাথে অনেকগুলি সমস্যা রয়েছে।

  1. HasFlag এটি টাইপ-সেফ নয় কারণ এটি কোনও প্রদত্ত এনাম টাইপ নয়, কোনও ধরণের এনাম মান আর্গুমেন্ট গ্রহণ করে।
  2. HasFlagদ্বিধাহীন, এটি এনাম মান আর্গুমেন্টের দ্বারা প্রদত্ত মান বা সমস্ত ফ্ল্যাগের মধ্যে আছে কিনা তা পরীক্ষা করে। সব কিছু ঠিক আছে।
  3. HasFlag বরং এটি ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে বক্সিং করার প্রয়োজন হয় যা বরাদ্দ দেয় এবং এইভাবে আরও আবর্জনা সংগ্রহের কারণ হয়।

.NET- র পতাকা enums গুলির জন্য সীমিত সহায়তার কারণে আমি ওএসএস লাইব্রেরি Enums.NET লিখেছিলাম যা এই প্রতিটি বিষয়কে সম্বোধন করে এবং পতাকা এনগমগুলির সাথে কাজ করা আরও সহজ করে তোলে।

নীচে কেবলমাত্র নেট নেট ফ্রেমওয়ার্ক ব্যবহার করে তাদের সমতুল্য বাস্তবায়ন সহ কিছু সরবরাহ করা অপারেশন রয়েছে।

পতাকা একত্রিত করুন

.NET             flags | otherFlags

Enums.NET flags.CombineFlags(otherFlags)


পতাকা সরান

.NET             flags & ~otherFlags

Enums.NET flags.RemoveFlags(otherFlags)


সাধারণ পতাকা

.NET             flags & otherFlags

Enums.NET flags.CommonFlags(otherFlags)


ফ্ল্যাগগুলি টগল করুন

.NET             flags ^ otherFlags

Enums.NET flags.ToggleFlags(otherFlags)


সমস্ত পতাকা আছে

.NET             (flags & otherFlags) == otherFlags বাflags.HasFlag(otherFlags)

Enums.NET flags.HasAllFlags(otherFlags)


কোন পতাকা আছে

.NET             (flags & otherFlags) != 0

Enums.NET flags.HasAnyFlags(otherFlags)


পতাকা পান

.NET

Enumerable.Range(0, 64)
  .Where(bit => ((flags.GetTypeCode() == TypeCode.UInt64 ? (long)(ulong)flags : Convert.ToInt64(flags)) & (1L << bit)) != 0)
  .Select(bit => Enum.ToObject(flags.GetType(), 1L << bit))`

Enums.NET flags.GetFlags()


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


7

সি ++ সিনট্যাক্স, বিট 0 টি এলএসবি হিসাবে ধরে নেওয়া, পতাকাগুলি স্বাক্ষরবিহীন দীর্ঘ বলে ধরে নেওয়া:

সেট করুন কিনা তা পরীক্ষা করুন:

flags & (1UL << (bit to test# - 1))

সেট না করা আছে কিনা তা পরীক্ষা করুন:

invert test !(flag & (...))

সেট করুন:

flag |= (1UL << (bit to set# - 1))

স্পষ্ট:

flag &= ~(1UL << (bit to clear# - 1))

টগল:

flag ^= (1UL << (bit to set# - 1))

3

সেরা পারফরম্যান্স এবং শূন্য আবর্জনার জন্য, এটি ব্যবহার করুন:

using System;
using T = MyNamespace.MyFlags;

namespace MyNamespace
{
    [Flags]
    public enum MyFlags
    {
        None = 0,
        Flag1 = 1,
        Flag2 = 2
    }

    static class MyFlagsEx
    {
        public static bool Has(this T type, T value)
        {
            return (type & value) == value;
        }

        public static bool Is(this T type, T value)
        {
            return type == value;
        }

        public static T Add(this T type, T value)
        {
            return type | value;
        }

        public static T Remove(this T type, T value)
        {
            return type & ~value;
        }
    }
}

2

কিছুটা পরীক্ষা করার জন্য আপনি নিম্নলিখিতগুলি করবেন: (পতাকাগুলি একটি 32 বিট সংখ্যা বলে ধরে নিচ্ছেন)

পরীক্ষার বিট:

if((flags & 0x08) == 0x08)
(যদি বিট 4 সেট করা হয় তবে এর সত্য) টগল ব্যাক (1 - 0 বা 0 - 1):
flags = flags ^ 0x08;
বিট 4 টি জিরোতে রিসেট করুন:
flags = flags & 0xFFFFFF7F;


2
-1 যেহেতু এটিও এনামদের নিয়ে মাথা ঘামায় না? এছাড়াও, মানগুলি হাত-কোডিং ভঙ্গুর ... আমি কমপক্ষে ~0x08পরিবর্তে লিখব 0xFFFFFFF7... (0x8 এর প্রকৃত মুখোশ)
বেন মোশার

1
প্রথমে আমি ভাবছিলাম যে বেন -1 কঠোর, তবে "0xFFFFFFFFF" এর ব্যবহার এটি একটি বিশেষ দরিদ্র উদাহরণ হিসাবে পরিণত করেছে।
টুলমেকারস্টেভ

2

এটি ডেলফির সূচক হিসাবে সেটগুলি ব্যবহার করে অনুপ্রাণিত হয়েছিল, যখন ফিরে এসেছিল:

/// Example of using a Boolean indexed property
/// to manipulate a [Flags] enum:

public class BindingFlagsIndexer
{
  BindingFlags flags = BindingFlags.Default;

  public BindingFlagsIndexer()
  {
  }

  public BindingFlagsIndexer( BindingFlags value )
  {
     this.flags = value;
  }

  public bool this[BindingFlags index]
  {
    get
    {
      return (this.flags & index) == index;
    }
    set( bool value )
    {
      if( value )
        this.flags |= index;
      else
        this.flags &= ~index;
    }
  }

  public BindingFlags Value 
  {
    get
    { 
      return flags;
    } 
    set( BindingFlags value ) 
    {
      this.flags = value;
    }
  }

  public static implicit operator BindingFlags( BindingFlagsIndexer src )
  {
     return src != null ? src.Value : BindingFlags.Default;
  }

  public static implicit operator BindingFlagsIndexer( BindingFlags src )
  {
     return new BindingFlagsIndexer( src );
  }

}

public static class Class1
{
  public static void Example()
  {
    BindingFlagsIndexer myFlags = new BindingFlagsIndexer();

    // Sets the flag(s) passed as the indexer:

    myFlags[BindingFlags.ExactBinding] = true;

    // Indexer can specify multiple flags at once:

    myFlags[BindingFlags.Instance | BindingFlags.Static] = true;

    // Get boolean indicating if specified flag(s) are set:

    bool flatten = myFlags[BindingFlags.FlattenHierarchy];

    // use | to test if multiple flags are set:

    bool isProtected = ! myFlags[BindingFlags.Public | BindingFlags.NonPublic];

  }
}

2
এমনকি যদি বাইন্ডিংফ্লাগগুলি বাইট এনাম হয় তবে এটি সংকলন করে না: this.flags & = ~ সূচক;
amular

0

সি ++ ক্রিয়াকলাপগুলি: & | । ~ (এবং, বা, xor এবং বিটওয়াইজ অপারেশন নয়)। আগ্রহের >> >> এবং << যা বিটশীট অপারেশন।

সুতরাং, পতাকাটিতে কিছুটা সেট হওয়ার জন্য পরীক্ষা করতে আপনি ব্যবহার করতে পারেন: যদি (পতাকা ও 8) // পরীক্ষার বিট 4 সেট করা থাকে


8
প্রশ্নটি সি # এর সাথে সম্পর্কিত, সি ++ নয়
অ্যান্ডি জনসন

3
অন্যদিকে, সি # একই অপারেটরগুলি ব্যবহার করে: এমএসডিএন.মাইক্রোসফটকম /en-us/library/6a71f45d.aspx
টুলমেকারস্টেভ

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