যদি আমার কাছে একটি এনগম ফ্ল্যাগ এনাম থাকে তবে আমি কি সেই নির্দিষ্ট ভেরিয়েবলের বিট মানগুলি নিয়ে পুনরাবৃত্তি করতে পারি? অথবা পুরো এনামের উপরে পুনরাবৃত্তি করতে এবং কোনটি সেট করা আছে তা পরীক্ষা করতে আমাকে এনাম.গেটভ্যালু ব্যবহার করতে হবে?
যদি আমার কাছে একটি এনগম ফ্ল্যাগ এনাম থাকে তবে আমি কি সেই নির্দিষ্ট ভেরিয়েবলের বিট মানগুলি নিয়ে পুনরাবৃত্তি করতে পারি? অথবা পুরো এনামের উপরে পুনরাবৃত্তি করতে এবং কোনটি সেট করা আছে তা পরীক্ষা করতে আমাকে এনাম.গেটভ্যালু ব্যবহার করতে হবে?
উত্তর:
static IEnumerable<Enum> GetFlags(Enum input)
{
foreach (Enum value in Enum.GetValues(input.GetType()))
if (input.HasFlag(value))
yield return value;
}
HasFlag
4 .NET 4 এর পরে উপলব্ধ।
Enum.GetValues(input.GetType()).Cast<Enum>().Where(input.HasFlag);
তারপরে ঠিক: myEnum.GetFLags()
:)
static IEnumerable<Enum> GetFlags(this Enum input)
সমস্যাটির একটি লিনক সমাধান এখানে।
public static IEnumerable<Enum> GetFlags(this Enum e)
{
return Enum.GetValues(e.GetType()).Cast<Enum>().Where(e.HasFlag);
}
.Where(v => !Equals((int)(object)v, 0) && e.HasFlag(v));
যদি শূন্যের মান থাকে তবে ব্যবহার করুনNone
আমার জানা মতে প্রতিটি উপাদান পাওয়ার জন্য কোনও বিল্টিন পদ্ধতি নেই। তবে এগুলি পাওয়ার জন্য এখানে একটি উপায় রয়েছে:
[Flags]
enum Items
{
None = 0x0,
Foo = 0x1,
Bar = 0x2,
Baz = 0x4,
Boo = 0x6,
}
var value = Items.Foo | Items.Bar;
var values = value.ToString()
.Split(new[] { ", " }, StringSplitOptions.None)
.Select(v => (Items)Enum.Parse(typeof(Items), v));
// This method will always end up with the most applicable values
value = Items.Bar | Items.Baz;
values = value.ToString()
.Split(new[] { ", " }, StringSplitOptions.None)
.Select(v => (Items)Enum.Parse(typeof(Items), v)); // Boo
আমি Enum
অভ্যন্তরীণভাবে স্ট্রিং তৈরি করতে ফ্ল্যাগগুলি ফিরিয়ে আনার জন্য যা রূপান্তরিত করেছি does আপনি কোডটি প্রতিফলকের দিকে দেখতে পারেন এবং কম বা বেশি সমতুল্য হওয়া উচিত। সাধারণ ব্যবহারের ক্ষেত্রে খুব ভাল কাজ করে যেখানে একাধিক বিট রয়েছে এমন মান রয়েছে।
static class EnumExtensions
{
public static IEnumerable<Enum> GetFlags(this Enum value)
{
return GetFlags(value, Enum.GetValues(value.GetType()).Cast<Enum>().ToArray());
}
public static IEnumerable<Enum> GetIndividualFlags(this Enum value)
{
return GetFlags(value, GetFlagValues(value.GetType()).ToArray());
}
private static IEnumerable<Enum> GetFlags(Enum value, Enum[] values)
{
ulong bits = Convert.ToUInt64(value);
List<Enum> results = new List<Enum>();
for (int i = values.Length - 1; i >= 0; i--)
{
ulong mask = Convert.ToUInt64(values[i]);
if (i == 0 && mask == 0L)
break;
if ((bits & mask) == mask)
{
results.Add(values[i]);
bits -= mask;
}
}
if (bits != 0L)
return Enumerable.Empty<Enum>();
if (Convert.ToUInt64(value) != 0L)
return results.Reverse<Enum>();
if (bits == Convert.ToUInt64(value) && values.Length > 0 && Convert.ToUInt64(values[0]) == 0L)
return values.Take(1);
return Enumerable.Empty<Enum>();
}
private static IEnumerable<Enum> GetFlagValues(Type enumType)
{
ulong flag = 0x1;
foreach (var value in Enum.GetValues(enumType).Cast<Enum>())
{
ulong bits = Convert.ToUInt64(value);
if (bits == 0L)
//yield return value;
continue; // skip the zero value
while (flag < bits) flag <<= 1;
if (flag == bits)
yield return value;
}
}
}
এক্সটেনশন পদ্ধতিটি GetIndividualFlags()
এক প্রকারের জন্য সমস্ত স্বতন্ত্র পতাকা পায়। সুতরাং একাধিক বিটযুক্ত মানগুলি বাদ পড়েছে।
var value = Items.Bar | Items.Baz;
value.GetFlags(); // Boo
value.GetIndividualFlags(); // Bar, Baz
Bar
, Baz
এবং Boo
পরিবর্তে শুধু Boo
।
Boo
(ব্যবহার করে মানটি ফিরে আসবে ToString()
)। আমি কেবল পৃথক পতাকা ব্যবহারের জন্য এটি টুইট করেছি। সুতরাং আমার উদাহরণে, আপনি পেতে পারেন Bar
এবং Baz
পরিবর্তে Boo
।
কয়েক বছর পরে এ ফিরে আসছি, আরও কিছু অভিজ্ঞতার সাথে, আমার একক-বিট মানগুলির চূড়ান্ত উত্তরটি, সর্বনিম্ন বিট থেকে সর্বোচ্চ বিটের দিকে চলে যাওয়া, জেফ মার্কাডোর অভ্যন্তরীণ রুটিন্যের সামান্য বৈকল্পিক:
public static IEnumerable<Enum> GetUniqueFlags(this Enum flags)
{
ulong flag = 1;
foreach (var value in Enum.GetValues(flags.GetType()).Cast<Enum>())
{
ulong bits = Convert.ToUInt64(value);
while (flag < bits)
{
flag <<= 1;
}
if (flag == bits && flags.HasFlag(value))
{
yield return value;
}
}
}
এটি কাজ করছে বলে মনে হচ্ছে এবং কয়েক বছর আগে আমার আপত্তি সত্ত্বেও আমি এখানে হ্যাসফ্ল্যাগ ব্যবহার করেছি, যেহেতু এটি বিটওয়াইজ তুলনা ব্যবহার করার চেয়ে অনেক বেশি সুশাস্ত্র এবং গতির তফাত আমি যে কিছু করব তার পক্ষে তাত্পর্যপূর্ণ। (এটি সম্পূর্ণরূপে সম্ভব যেহেতু তারা যাইহোক হ্যাশফ্লাগগুলির গতি উন্নত করেছে, আমি জানি সকলের জন্য ... আমি পরীক্ষা করিনি))
yield return bits;
?
@ গ্রেগের পদ্ধতিটি বন্ধ করা হচ্ছে, তবে সি # 7.3 থেকে একটি নতুন বৈশিষ্ট্য যুক্ত করা, এই Enum
সীমাবদ্ধতা:
public static IEnumerable<T> GetUniqueFlags<T>(this Enum flags)
where T : Enum // New constraint for C# 7.3
{
foreach (Enum value in Enum.GetValues(flags.GetType()))
if (flags.HasFlag(value))
yield return (T)value;
}
নতুন বাধ্যতা মাধ্যমে নিক্ষেপ করেও, এই একটি এক্সটেনশন পদ্ধতি হতে পারবেন (int)(object)e
, এবং আমি ব্যবহার করতে পারেন HasFlag
সরাসরি পদ্ধতি এবং ঢালাই T
থেকে value
।
সি # 7.3 এছাড়াও ডেলাগেট এবং এর জন্য প্রতিবন্ধকতা যুক্ত করেছে unmanaged
।
flags
প্যারামিটারটি জেনেরিক প্রকারের হতে চেয়েছিলেন T
, অন্যথায় আপনি যতবারই কল করবেন প্রত্যেকবার আপনাকে অবশ্যই এনাম টাইপটি স্পষ্টভাবে উল্লেখ করতে হবে।
@ রবিনহুড 70 দ্বারা সরবরাহিত উত্তরের জন্য +1। আমি খুঁজে পেয়েছি যে পদ্ধতির জেনেরিক সংস্করণটি আমার পক্ষে সুবিধাজনক।
public static IEnumerable<T> GetUniqueFlags<T>(this Enum flags)
{
if (!typeof(T).IsEnum)
throw new ArgumentException("The generic type parameter must be an Enum.");
if (flags.GetType() != typeof(T))
throw new ArgumentException("The generic type parameter does not match the target type.");
ulong flag = 1;
foreach (var value in Enum.GetValues(flags.GetType()).Cast<T>())
{
ulong bits = Convert.ToUInt64(value);
while (flag < bits)
{
flag <<= 1;
}
if (flag == bits && flags.HasFlag(value as Enum))
{
yield return value;
}
}
}
সমাধানের জায়গায় সি # 7.3 আনার জন্য @ অস্টিন ডাব্লু ব্রায়ানের জন্য সম্পাদনা করুন এবং +1 করুন।
public static IEnumerable<T> GetUniqueFlags<T>(this T flags) where T : Enum
{
ulong flag = 1;
foreach (var value in Enum.GetValues(flags.GetType()).Cast<T>())
{
ulong bits = Convert.ToUInt64(value);
while (flag < bits)
{
flag <<= 1;
}
if (flag == bits && flags.HasFlag(value as Enum))
{
yield return value;
}
}
}
আপনাকে সমস্ত মান পুনরাবৃত্তি করতে হবে না। আপনার নির্দিষ্ট ফ্ল্যাগগুলি কেবল এর মতো পরীক্ষা করুন:
if((myVar & FlagsEnum.Flag1) == FlagsEnum.Flag1)
{
//do something...
}
বা (যেমন পিএসটিজেডস মন্তব্যে বলেছে) আপনি এটির মতো ব্যবহারের জন্য এটি পরীক্ষা করতে পারেন:
if(myVar.HasFlag(FlagsEnum.Flag1))
{
//do something...
}
আমি যা করেছি তা ছিল আমার পদ্ধতির পরিবর্তন, পদ্ধতির ইনপুট প্যারামিটারটি টাইপ হিসাবে টাইপ করার পরিবর্তে enum
, আমি এটিকে enum
টাইপ ( MyEnum[] myEnums
) এর অ্যারে হিসাবে টাইপ করেছি , এইভাবে আমি কেবল লুপের অভ্যন্তরে একটি সুইচ বিবৃতি দিয়ে অ্যারের মাধ্যমে পুনরাবৃত্তি করি।
উপরের উত্তরগুলির সাথে সন্তুষ্ট ছিল না, যদিও তারা শুরু ছিল।
এখানে কিছু ভিন্ন উত্স একসাথে
পাইক করার পরে: এই থ্রেডের এসও কিউএনএ
কোড প্রকল্পের পূর্ববর্তী পোস্টার এনুম ফ্ল্যাগগুলি চেক পোস্ট
গ্রেট এনাম <টি> ইউটিলিটি
আমি এটি তৈরি করেছি যাতে আপনি কী ভাবছেন তা আমাকে জানান।
পরামিতি::
bool checkZero
এটি 0
একটি পতাকা মান হিসাবে অনুমতি দিতে বলে । ডিফল্টরূপে input = 0
খালি ফিরে আসে।
bool checkFlags
: এটি Enum
ডাব্লু / [Flags]
বৈশিষ্ট্যটি সজ্জিত কিনা তা পরীক্ষা করতে বলে।
পুনশ্চ. checkCombinators = false
আলগ বের করার জন্য আমার কাছে এখনই সময় নেই যা এটি বিটের সংমিশ্রণে থাকা কোনও এনাম মানগুলিকে উপেক্ষা করতে বাধ্য করবে।
public static IEnumerable<TEnum> GetFlags<TEnum>(this TEnum input, bool checkZero = false, bool checkFlags = true, bool checkCombinators = true)
{
Type enumType = typeof(TEnum);
if (!enumType.IsEnum)
yield break;
ulong setBits = Convert.ToUInt64(input);
// if no flags are set, return empty
if (!checkZero && (0 == setBits))
yield break;
// if it's not a flag enum, return empty
if (checkFlags && !input.GetType().IsDefined(typeof(FlagsAttribute), false))
yield break;
if (checkCombinators)
{
// check each enum value mask if it is in input bits
foreach (TEnum value in Enum<TEnum>.GetValues())
{
ulong valMask = Convert.ToUInt64(value);
if ((setBits & valMask) == valMask)
yield return value;
}
}
else
{
// check each enum value mask if it is in input bits
foreach (TEnum value in Enum <TEnum>.GetValues())
{
ulong valMask = Convert.ToUInt64(value);
if ((setBits & valMask) == valMask)
yield return value;
}
}
}
এটি হেল্পার ক্লাস এনাম <T> এখানে ব্যবহার yield return
করেছে যা আমি এর জন্য ব্যবহার করতে আপডেট করেছি GetValues
:
public static class Enum<TEnum>
{
public static TEnum Parse(string value)
{
return (TEnum)Enum.Parse(typeof(TEnum), value);
}
public static IEnumerable<TEnum> GetValues()
{
foreach (object value in Enum.GetValues(typeof(TEnum)))
yield return ((TEnum)value);
}
}
অবশেষে, এটি ব্যবহারের উদাহরণ এখানে:
private List<CountType> GetCountTypes(CountType countTypes)
{
List<CountType> cts = new List<CountType>();
foreach (var ct in countTypes.GetFlags())
cts.Add(ct);
return cts;
}
উপরের গ্রেগের উত্তরের উপর ভিত্তি করে, এটি আপনার এনামে যেখানে 0 মান রয়েছে এমন ক্ষেত্রেও যত্ন নেবে, যেমন কোনওটি নয় = 0 কোন ক্ষেত্রে এটির মানটি পুনরাবৃত্তি করা উচিত নয়।
public static IEnumerable<Enum> ToEnumerable(this Enum input)
{
foreach (Enum value in Enum.GetValues(input.GetType()))
if (input.HasFlag(value) && Convert.ToInt64(value) != 0)
yield return value;
}
যে কেউ আরও কীভাবে এটির উন্নতি করতে জানতে পারে যাতে এনামের সমস্ত পতাকা একটি দুর্দান্ত স্মার্ট উপায়ে সেট করা থাকে যা সমস্ত অন্তর্নিহিত এনাম প্রকার এবং সমস্ত = ~ 0 এবং সমস্ত = এনামভ্যালু 1 | কে পরিচালনা করতে পারে handle এনামভ্যালু 2 | এনামভ্যালু 3 | ...
আপনি এনাম থেকে একজন আইট্রেটর ব্যবহার করতে পারেন। এমএসডিএন কোড থেকে শুরু:
public class DaysOfTheWeek : System.Collections.IEnumerable
{
int[] dayflag = { 1, 2, 4, 8, 16, 32, 64 };
string[] days = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
public string value { get; set; }
public System.Collections.IEnumerator GetEnumerator()
{
for (int i = 0; i < days.Length; i++)
{
if value >> i & 1 == dayflag[i] {
yield return days[i];
}
}
}
}
এটি পরীক্ষা করা হয় না, তাই যদি আমি কোনও ভুল করি তবে নির্দ্বিধায় আমাকে কল করে। (স্পষ্টতই এটি পুনরায় প্রবেশকারী নয়)) আপনাকে আগেই মান নির্ধারণ করতে হবে, বা এটি অন্য কোনও ফাংশনে ভাঙতে হবে যা enum.dayflag এবং enum.days ব্যবহার করে। আপনি হয়ত রূপরেখা দিয়ে কোথাও যেতে পারবেন।
এটি নিম্নলিখিত কোড হিসাবে পাশাপাশি হতে পারে:
public static string GetEnumString(MyEnum inEnumValue)
{
StringBuilder sb = new StringBuilder();
foreach (MyEnum e in Enum.GetValues(typeof(MyEnum )))
{
if ((e & inEnumValue) != 0)
{
sb.Append(e.ToString());
sb.Append(", ");
}
}
return sb.ToString().Trim().TrimEnd(',');
}
এটি কেবল তখনই প্রবেশ করতে পারে যখন এনাম মানটি থাকে
সমস্ত উত্তরগুলি সহজ পতাকাগুলির সাথে ভালভাবে কাজ করে, পতাকাগুলি একত্রিত করার সময় আপনি সম্ভবত সমস্যাগুলির মধ্যে চলে যাবেন।
[Flags]
enum Food
{
None=0
Bread=1,
Pasta=2,
Apples=4,
Banana=8,
WithGluten=Bread|Pasta,
Fruits = Apples | Banana,
}
এনামের মান এটি একটি সংমিশ্রণ হয় কিনা তা পরীক্ষা করার জন্য সম্ভবত একটি চেক যুক্ত করা দরকার। আপনার প্রয়োজনীয়তাটি কমাতে আপনার সম্ভবত হেন্ক ভ্যান বোয়েজেন পোস্ট করার মতো কিছু দরকার ছিল (আপনার কিছুটা নিচে স্ক্রোল করতে হবে)
Enালাই রোধ করতে নতুন এনুম সীমাবদ্ধতা এবং জেনেরিকগুলি ব্যবহার করে এক্সটেনশন পদ্ধতি:
public static class EnumExtensions
{
public static T[] GetFlags<T>(this T flagsEnumValue) where T : Enum
{
return Enum
.GetValues(typeof(T))
.Cast<T>()
.Where(e => flagsEnumValue.HasFlag(e))
.ToArray();
}
}
আপনি সরাসরি ইন-তে রূপান্তর করে এটি করতে পারেন তবে আপনি টাইপ চেক করতে পারেন। আমি মনে করি সবচেয়ে ভাল উপায় হ'ল আমার প্রস্তাবের অনুরূপ কিছু ব্যবহার করা। এটি পুরোপুরি সঠিক টাইপ রাখে। কোনও রূপান্তর প্রয়োজন। বক্সিংয়ের কারণে এটি নিখুঁত নয় যা পারফরম্যান্সে কিছুটা হিট যোগ করবে।
নিখুঁত (বক্সিং) নয়, তবে এটি কোনও সতর্কতা ছাড়াই কাজ করে ...
/// <summary>
/// Return an enumerators of input flag(s)
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public static IEnumerable<T> GetFlags<T>(this T input)
{
foreach (Enum value in Enum.GetValues(input.GetType()))
{
if ((int) (object) value != 0) // Just in case somebody has defined an enum with 0.
{
if (((Enum) (object) input).HasFlag(value))
yield return (T) (object) value;
}
}
}
ব্যবহার:
FileAttributes att = FileAttributes.Normal | FileAttributes.Compressed;
foreach (FileAttributes fa in att.GetFlags())
{
...
}