এনাম জেনেরিক সীমাবদ্ধতার অভাবের জন্য যে কেউ ভাল কাজ জানেন?


90

আমি যা করতে চাই তা হ'ল: আমি সম্মিলিত পতাকাযুক্ত মান সহ এনাম আছে।

public static class EnumExtension
{
    public static bool IsSet<T>( 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

দুর্ভাগ্যক্রমে, সি # এর জেনেরিক যেখানে সীমাবদ্ধতার কোনও এনাম বাধা নেই, কেবল শ্রেণি এবং কাঠামো। সি # এনামগুলিকে স্ট্রাক্ট হিসাবে দেখেনি (যদিও তারা মান ধরণের হয়) সুতরাং আমি এর মতো এক্সটেনশান ধরণের যুক্ত করতে পারি না।

কেউ কি কাজের কথা জানে?


4
কীথ: আনকন্ট্রেনডমেলডি-র 0.0.0.2 সংস্করণ ডাউনলোড করুন - আমি হাসআল এবং হাসআনি প্রয়োগ করেছি। উপভোগ করুন
জন স্কিটি

"সি # এর দ্বারা এনামগুলিকে স্ট্রাক্ট হিসাবে দেখা যায় না" এর অর্থ কী? আপনি এনাম টাইপগুলিকে টাইপ পরামিতি হিসাবে ব্যবহার করতে পারেন যা structকেবল জরিমানা করতে বাধ্য ।
টিমউই

এই নিবন্ধটি এখানে চেক করুন: কোডেপ্রজেক্ট / কেবি / সিএস / এক্সটেন্ডইনাম.এএসপিএক্স 'ইসভালিডেনমভ্যালু' বা 'ইসফ্লাগসইনামডিফাইনড' পদ্ধতিগুলি সম্ভবত আপনার প্রশ্নের উত্তর।
dmihailescu

4
এই ব্যবহারকারীভয়েস ধারণার পক্ষে ভোট দিন , যদি আপনি এটি অন্তর্নির্মিত। নেট একদিন দেখতে চান।
ম্যাথিউউ

11
সি # 7.3 এনাম সীমাবদ্ধতার পরিচয় দেয়।
মার্ক সিগ্রিস্ট

উত্তর:


49

সম্পাদনা: এটি এখন আনকন্সট্রেন্ডডমেলডি এর 0.0.0.2 সংস্করণে লাইভ।

( এনাম প্রতিবন্ধকতা সম্পর্কে আমার ব্লগ পোস্টে অনুরোধ করা হয়েছে । আমি স্বতন্ত্র উত্তরের জন্য নীচের মূল তথ্যগুলি অন্তর্ভুক্ত করেছি।)

আনকন্সট্রেন্ডডমেলডি 1 এ অন্তর্ভুক্ত করার জন্য আমার অপেক্ষা করা সবচেয়ে ভাল সমাধান । এটি একটি লাইব্রেরি যা "নকল" সীমাবদ্ধতার সাথে সি # কোড নেয়

where T : struct, IEnumConstraint

এবং এটি পরিণত

where T : struct, System.Enum

একটি পোস্ট বিল্ডিং পদক্ষেপের মাধ্যমে।

এটি লেখা খুব কঠিন হওয়া উচিত নয় IsSet... যদিও Int64ভিত্তিযুক্ত এবং UInt64ভিত্তিক উভয় ফ্ল্যাগের জন্য খাদ্য সরবরাহ করা জটিল অংশ হতে পারে। (আমি কিছু সহায়ক পদ্ধতির ঘ্রাণ নিচ্ছি যা মূলত আমাকে যে কোনও পতাকা এনামের সাথে চিকিত্সা করার অনুমতি দেয় যেন এটির বেস টাইপ রয়েছে UInt64))

আপনি ফোন করলে আচরণটি কী হতে চান

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

? এটি নির্দিষ্ট করা সমস্ত পতাকা সেট করা আছে কিনা তা পরীক্ষা করা উচিত ? এটা আমার প্রত্যাশা হবে।

আমি আজ রাতে বাড়ির পথে এটি করার চেষ্টা করব ... আমি আশা করছি যে দরকারী গ্রন্থাগারটি ব্যবহারযোগ্য মান দ্রুত পৌঁছে দেওয়ার জন্য দরকারী এনাম পদ্ধতিগুলির উপর একটি দ্রুত ব্লিটস লাগবে, তারপরে কিছুটা বিশ্রাম নিন।

সম্পাদনা: আমি IsSetকোনও নাম হিসাবে নিশ্চিত নই , উপায় দ্বারা। বিকল্পসমূহ:

  • অন্তর্ভুক্ত
  • ধারণ করে
  • হাসফ্লেগ (বা হ্যাসফ্ল্যাগস)
  • ইসসেট (এটি অবশ্যই একটি বিকল্প)

চিন্তা স্বাগত জানাই। আমি নিশ্চিত যে যাইহোক পাথর স্থাপনের কিছুক্ষণ আগে ...


1 বা এটি প্যাচ হিসাবে জমা দিন অবশ্যই ...


4
আপনাকে গিয়ে পোস্টশার্প এলওএল উল্লেখ করতে হবে: o পোষ্টশার্প.আর
স্যাম

4
বা আসলেই সহজ সরল হাসান () এবং হাসআল ()
কিথ

4
হ্যাঁ, আমি এটি আরও ভাল সম্মত। colors.HasAny(Colors.Red | Colors.Blue)খুব পঠনযোগ্য কোডের মতো দেখাচ্ছে। =)
Blixt

4
হ্যাঁ, আমি হাস্যানি এবং হাসআলকেও পছন্দ করি। সাথে যেতে হবে।
জন স্কিটি

4
যেহেতু সি # 7.3 (মে 2018 প্রকাশিত হয়েছে), সীমাবদ্ধতাটি ব্যবহার করা সম্ভব where T : System.Enum। এটি ইতিমধ্যে থ্রেডের অন্যত্র লেখা হয়েছিল; আমি ভেবেছিলাম আমি এখানে এটি পুনরাবৃত্তি করব।
জেপ্পে স্টিগ নীলসেন


16

ড্যারেন, এটি কাজ করবে যদি প্রকারগুলি নির্দিষ্ট গণনাগুলি ছিল - সাধারণ গণনার কাজ করার জন্য আপনাকে সেগুলি বুটিন গণিত করার জন্য অন্তর্বাসগুলিতে (বা সম্ভবত আরও বেশি পরিমাণে) দিতে হবে:

public static bool IsSet( this Enum input, Enum matchTo )
{
    return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}

4
এবং যদি আপনার একটি হাস্যকর পতাকা রয়েছে তবে আপনি আর্গুমেন্ট এবং কনভার্টে getTypeCode () কল করতে পারেন oToUint64 ()
কিট

দুর্দান্ত, 'এনুমা'র সংমিশ্রণটি Convert.ToUInt32আমি আর কোথাও খুঁজে পাইনি। আফাইক, এটি একমাত্র শালীন প্রাক নেট -4 সমাধান যা ভিবিতেও কাজ করে। BTW, যদি matchToশক্তি একাধিক পতাকা বিট থাকে, তখন প্রতিস্থাপন != 0সঙ্গে == Convert.ToUInt32(matchTo)
টুলমেকারস্টেভ

4
নোট করুন যে Convert.ToUInt32এনামের সাথে ব্যবহার করা হয়েছে ওভারলোডটি ব্যবহার করবে Convert.ToUInt32(object), যার অর্থ সিএলআর প্রথমে প্রথমে এই মানগুলি প্রথমে ToUInt32পদ্ধতিতে যাওয়ার আগে বাক্স করবে । বেশিরভাগ ক্ষেত্রে এটি কোনও ব্যাপার নয়, তবে এটি জেনে রাখা ভাল আপনি যদি সেকেন্ডে কয়েক মিলিয়ন এনাম পার্স করার জন্য এই জাতীয় কিছু ব্যবহার করেন তবে আপনি জিসিকে বরং ব্যস্ত রাখবেন।
গ্রো 15

10

আসলে, এটি একটি কুৎসিত কৌতুক দিয়ে সম্ভব। তবে এটি এক্সটেনশন পদ্ধতিগুলির জন্য ব্যবহার করা যাবে না।

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

Enums.IsSet<DateTimeKind>("Local")

আপনি করতে চান তাহলে, আপনি দিতে পারেন Enums<Temp>একটি প্রাইভেট কন্সট্রাকটর এবং একটি পাবলিক নেস্টেড বিমূর্ত উত্তরাধিকারসূত্রে বর্গ Tempহিসাবে Enum, অ-enums জন্য উত্তরাধিকারসূত্রে সংস্করণ প্রতিরোধ।


8

আইএল বয়ন এবং এক্সট্রা কনস্ট্রাইটস ব্যবহার করে আপনি এটি অর্জন করতে পারেন

আপনাকে এই কোডটি লেখার অনুমতি দেয়

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

কি সংকলিত হয়

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

    public void MethodWithEnumConstraint<T>() where T: struct, Enum
    {
    }
}

6

সি # 7.3 হিসাবে, আপনি জেনেরিক ধরণের উপর এনুম সীমাবদ্ধতা ব্যবহার করতে পারেন:

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

আপনি যদি একটি নলযোগ্য এনাম ব্যবহার করতে চান তবে আপনাকে অবশ্যই অরিজিনাল স্ট্রাক্ট সীমাবদ্ধতাটি ছেড়ে দিতে হবে:

public static TEnum? TryParse<TEnum>(string value) where TEnum : struct, Enum
{
    if( Enum.TryParse(value, out TEnum res) )
        return res;
    else
        return null;
}

4

এটি আসল প্রশ্নের উত্তর দেয় না, তবে এনট 4 নামক নেট 4 এ এখন একটি পদ্ধতি রয়েছে যা হ্যাসফ্লেগ যা আপনার উদাহরণে আপনি যা করার চেষ্টা করছেন তা করে


উত্সাহিত করা হয়েছে কারণ এই মুহুর্তে, প্রত্যেকেরই .NET 4 (বা উচ্চতর) ব্যবহার করা উচিত এবং সুতরাং তাদের একসাথে হ্যাক করার চেষ্টা করার পরিবর্তে এই পদ্ধতিটি ব্যবহার করা উচিত।
সিটিপি রবি

উত্সাহিত। তবে তাদের সমাধান যুক্তিটির বক্সিং ব্যবহার করে flag। .NET 4.0 এখন পাঁচ বছর বয়সী।
জেপ্প স্টিগ নীলসেন

3

আমি যেভাবে এটি করি তাতে একটি কাঠামো বাধা দেওয়া হয়, তারপরে পরীক্ষা করুন যে রানটাইম সময় টি এনাম। এটি সমস্যাটি পুরোপুরি সরিয়ে দেয় না, তবে এটি কিছুটা হ্রাস করে


7
যেখানে টি: স্ট্রাক্ট, আইকনপ্যামেবল, আইফোর্মেটেবল, আইকনভারটিবল - এটি আপনি সবচেয়ে কাছের এটি পেতে পারেন :)
কিট

1

আপনার মূল কোডটি ব্যবহার করে, পদ্ধতির অভ্যন্তরে আপনি পরীক্ষা করতেও প্রতিবিম্ব ব্যবহার করতে পারেন যে টি একটি এনাম:

public static class EnumExtension
{
    public static bool IsSet<T>( this T input, T matchTo )
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("Must be an enum", "input");
        }
        return (input & matchTo) != 0;
    }
}

4
ধন্যবাদ, তবে এটি একটি সংকলন সময়ের ইস্যু (যেখানে সীমাবদ্ধতা) রানটাইম একে (আপনার ব্যতিক্রম) রূপান্তরিত করে। এছাড়াও ইনপুটগুলির সাথে কিছু করার আগে আপনাকে ইনপুটগুলিতে রূপান্তর করতে হবে।
কিথ

1

এখানে এমন কিছু কোড রয়েছে যা আমি সবেমাত্র করেছি যা দেখে মনে হয় আপনার মতো কাজ করা খুব বেশি পাগল না করে। এটি কেবল পতাকা হিসাবে সেট করা এনামগুলিতেই সীমাবদ্ধ নয়, তবে প্রয়োজনে সর্বদা একটি চেক লাগানো যেতে পারে।

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

যদি কারও জেনেরিক ইসসেটের প্রয়োজন হয় (ফ্লাইয়ের বাক্সের বাইরে তৈরি করা উন্নত করা যেতে পারে), বা এনাম অনফ্লাই রূপান্তর (যা নীচে উপস্থাপিত এনামকনস্ট্রেন্ট ব্যবহার করে) এর স্ট্রিং রয়েছে:

  public class TestClass
  { }

  public struct TestStruct
  { }

  public enum TestEnum
  {
    e1,    
    e2,
    e3
  }

  public static class TestEnumConstraintExtenssion
  {

    public static bool IsSet<TEnum>(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<TestClass>(_this);
    //}

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

    public static TestEnum ToTestEnum(this string _this)
    {
      // #enum type works just fine (coding constraint to Enum type)
      return EnumConstraint.TryParse<TestEnum>(_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>(TestEnum.e2); // you can specify explicite type

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

    }

  }

এনাম কোডিং সীমাবদ্ধতা তৈরি করতে কারও যদি এখনও গরমের উদাহরণ প্রয়োজন হয়:

using System;

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

}

/// <summary>
/// provides ability to constrain TEnum to System.Enum abusing constrain inheritence
/// </summary>
/// <typeparam name="TClass">should be System.Enum</typeparam>
public abstract class EnumConstraint_T<TClass>
  where TClass : class
{

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

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

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

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

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

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

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

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

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

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

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

}

আশা করি এটি কাউকে সাহায্য করবে


0

আমি কেবল জেনেরিক সীমাবদ্ধতা হিসাবে এনামকে যুক্ত করতে চেয়েছিলাম।

যদিও এটি কেবলমাত্র একটি ক্ষুদ্র সাহায্যকারী পদ্ধতির ExtraConstraintsজন্য আমার পক্ষে কিছুটা বেশি ওভারহেড using

আমি ঠিক করেছি একটি structসীমাবদ্ধতা তৈরি করব এবং এর জন্য একটি রানটাইম চেক যুক্ত করব IsEnum। একটি পরিবর্তনশীল টি থেকে এনামে রূপান্তর করার জন্য আমি প্রথমে এটি বস্তুতে ফেলেছি।

    public static Converter<T, string> CreateConverter<T>() where T : struct
    {
        if (!typeof(T).IsEnum) throw new ArgumentException("Given Type is not an Enum");
        return new Converter<T, string>(x => ((Enum)(object)x).GetEnumDescription());
    }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.