সি # তে ইন্টিগ্রেশনটি আইনী এনাম কিনা তা পরীক্ষা করার কোনও উপায় আছে?


167

আমি কয়েকটি এসও পোস্ট পড়েছি এবং মনে হয় বেশিরভাগ বুনিয়াদি অপারেশনটি অনুপস্থিত।

public enum LoggingLevel
{
    Off = 0,
    Error = 1,
    Warning = 2,
    Info = 3,
    Debug = 4,
    Trace = 5
};

if (s == "LogLevel")
{
    _log.LogLevel = (LoggingLevel)Convert.ToInt32("78");
    _log.LogLevel = (LoggingLevel)Enum.Parse(typeof(LoggingLevel), "78");
    _log.WriteDebug(_log.LogLevel.ToString());
}

এটি কোনও ব্যতিক্রম ঘটায় না, এটি সঞ্চয় করে খুশি 78। এনামে যাবার মানটি যাচাই করার কোনও উপায় আছে কি?


উত্তর:


271

এনাম.আইএসডিফাইনড দেখুন Check

ব্যবহার:

if(Enum.IsDefined(typeof(MyEnum), value))
    MyEnum a = (MyEnum)value; 

এই পৃষ্ঠা থেকে এই উদাহরণ:

using System;    
[Flags] public enum PetType
{
   None = 0, Dog = 1, Cat = 2, Rodent = 4, Bird = 8, Reptile = 16, Other = 32
};

public class Example
{
   public static void Main()
   {
      object value;     
      // Call IsDefined with underlying integral value of member.
      value = 1;
      Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
      // Call IsDefined with invalid underlying integral value.
      value = 64;
      Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
      // Call IsDefined with string containing member name.
      value = "Rodent";
      Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
      // Call IsDefined with a variable of type PetType.
      value = PetType.Dog;
      Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
      value = PetType.Dog | PetType.Cat;
      Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
      // Call IsDefined with uppercase member name.      
      value = "None";
      Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
      value = "NONE";
      Console.WriteLine("{0}: {1}", value, Enum.IsDefined(typeof(PetType), value));
      // Call IsDefined with combined value
      value = PetType.Dog | PetType.Bird;
      Console.WriteLine("{0:D}: {1}", value, Enum.IsDefined(typeof(PetType), value));
      value = value.ToString();
      Console.WriteLine("{0:D}: {1}", value, Enum.IsDefined(typeof(PetType), value));
   }
}

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

//       1: True
//       64: False
//       Rodent: True
//       Dog: True
//       Dog, Cat: False
//       None: True
//       NONE: False
//       9: False
//       Dog, Bird: False

@ মট্টি: "78" কে যত সংখ্যক উপস্থাপনা LoggingLevelস্টোরেজ হিসাবে ব্যবহার করে তা রূপান্তর করুন , তারপরে এটি LoggingLevelএনাম মান হিসাবে উপস্থাপন করুন ।
কোকুপ

9
মনে IsDefinedহচ্ছে বিটউইজড এনাম সদস্যদের জন্য কাজ করছে না।
সা Saeedদ নেমতি

29

উপরের সমাধানগুলি [Flags]পরিস্থিতিগুলি মোকাবেলা করে না ।

নীচে আমার সমাধানে কিছু পারফরম্যান্স সমস্যা থাকতে পারে (আমি নিশ্চিত যে বিভিন্ন উপায়ে কেউ অনুকূলিত করতে পারে) তবে মূলত এটি সর্বদা প্রমাণ করবে যে এনাম মানটি বৈধ কিনা

এটি তিনটি অনুমানের উপর নির্ভর করে:

  • সি # তে এনাম মানগুলি কেবলমাত্র অনুমোদিত int, অন্য কিছু নয় absolutely
  • সি # তে এনাম নামগুলি বর্ণমালার অক্ষর দিয়ে শুরু হওয়া উচিত
  • কোনও বৈধ এনাম নাম বিয়োগ চিহ্ন সহ হতে পারে না: -

ToString()কোনও এনামের সাথে কল করা কোনও intমান (পতাকা বা না) মিললে মানটি দেয় returns যদি অনুমোদিত এনুম মানটি মিলে যায় তবে এটি ম্যাচের নাম (এস) প্রিন্ট করবে।

তাই:

[Flags]
enum WithFlags
{
    First = 1,
    Second = 2,
    Third = 4,
    Fourth = 8
}

((WithFlags)2).ToString() ==> "Second"
((WithFlags)(2 + 4)).ToString() ==> "Second, Third"
((WithFlags)20).ToString() ==> "20"

এই দুটি নিয়ম মাথায় রেখে আমরা ধরে নিতে পারি যে .NET ফ্রেমওয়ার্কটি যদি সঠিকভাবে কাজ করে যে কোনও বৈধ এনামের ToString()পদ্ধতিতে যে কোনও কল করার ফলে এটির প্রথম অক্ষর হিসাবে বর্ণানুক্রমিক অক্ষর রয়েছে এমন কিছু ঘটবে:

public static bool IsValid<TEnum>(this TEnum enumValue)
    where TEnum : struct
{
    var firstChar = enumValue.ToString()[0];
    return (firstChar < '0' || firstChar > '9') && firstChar != '-';
}

একে একে "হ্যাক" বলা যেতে পারে তবে সুবিধাগুলি হ'ল মাইক্রোসফ্টের নিজস্ব প্রয়োগ Enumএবং সি # মানদণ্ডের উপর নির্ভর করে আপনি নিজের সম্ভাব্য বগি কোড বা চেকগুলিতে নির্ভর করছেন না। এমন পরিস্থিতিতে যেখানে পারফরম্যান্স ব্যতিক্রমীভাবে সমালোচনামূলক নয়, এটি প্রচুর বাজে switchবিবৃতি বা অন্যান্য চেক সংরক্ষণ করবে !

সম্পাদন করা

আমার আসল বাস্তবায়ন নেতিবাচক মানগুলিকে সমর্থন করে না বলে উল্লেখ করার জন্য @ চেসেমেডালিয়নকে ধন্যবাদ। এটি প্রতিকার এবং পরীক্ষা প্রদান করা হয়েছে।

এবং পরীক্ষাগুলি এটি ব্যাক আপ করার জন্য:

[TestClass]
public class EnumExtensionsTests
{
    [Flags]
    enum WithFlags
    {
        First = 1,
        Second = 2,
        Third = 4,
        Fourth = 8
    }

    enum WithoutFlags
    {
        First = 1,
        Second = 22,
        Third = 55,
        Fourth = 13,
        Fifth = 127
    }

    enum WithoutNumbers
    {
        First, // 1
        Second, // 2
        Third, // 3
        Fourth // 4
    }

    enum WithoutFirstNumberAssigned
    {
        First = 7,
        Second, // 8
        Third, // 9
        Fourth // 10
    }


    enum WithNagativeNumbers
    {
        First = -7,
        Second = -8,
        Third = -9,
        Fourth = -10
    }

    [TestMethod]
    public void IsValidEnumTests()
    {
        Assert.IsTrue(((WithFlags)(1 | 4)).IsValid());
        Assert.IsTrue(((WithFlags)(1 | 4)).IsValid());
        Assert.IsTrue(((WithFlags)(1 | 4 | 2)).IsValid());
        Assert.IsTrue(((WithFlags)(2)).IsValid());
        Assert.IsTrue(((WithFlags)(3)).IsValid());
        Assert.IsTrue(((WithFlags)(1 + 2 + 4 + 8)).IsValid());

        Assert.IsFalse(((WithFlags)(16)).IsValid());
        Assert.IsFalse(((WithFlags)(17)).IsValid());
        Assert.IsFalse(((WithFlags)(18)).IsValid());
        Assert.IsFalse(((WithFlags)(0)).IsValid());

        Assert.IsTrue(((WithoutFlags)1).IsValid());
        Assert.IsTrue(((WithoutFlags)22).IsValid());
        Assert.IsTrue(((WithoutFlags)(53 | 6)).IsValid());   // Will end up being Third
        Assert.IsTrue(((WithoutFlags)(22 | 25 | 99)).IsValid()); // Will end up being Fifth
        Assert.IsTrue(((WithoutFlags)55).IsValid());
        Assert.IsTrue(((WithoutFlags)127).IsValid());

        Assert.IsFalse(((WithoutFlags)48).IsValid());
        Assert.IsFalse(((WithoutFlags)50).IsValid());
        Assert.IsFalse(((WithoutFlags)(1 | 22)).IsValid());
        Assert.IsFalse(((WithoutFlags)(9 | 27 | 4)).IsValid());

        Assert.IsTrue(((WithoutNumbers)0).IsValid());
        Assert.IsTrue(((WithoutNumbers)1).IsValid());
        Assert.IsTrue(((WithoutNumbers)2).IsValid());
        Assert.IsTrue(((WithoutNumbers)3).IsValid());
        Assert.IsTrue(((WithoutNumbers)(1 | 2)).IsValid()); // Will end up being Third
        Assert.IsTrue(((WithoutNumbers)(1 + 2)).IsValid()); // Will end up being Third

        Assert.IsFalse(((WithoutNumbers)4).IsValid());
        Assert.IsFalse(((WithoutNumbers)5).IsValid());
        Assert.IsFalse(((WithoutNumbers)25).IsValid());
        Assert.IsFalse(((WithoutNumbers)(1 + 2 + 3)).IsValid());

        Assert.IsTrue(((WithoutFirstNumberAssigned)7).IsValid());
        Assert.IsTrue(((WithoutFirstNumberAssigned)8).IsValid());
        Assert.IsTrue(((WithoutFirstNumberAssigned)9).IsValid());
        Assert.IsTrue(((WithoutFirstNumberAssigned)10).IsValid());

        Assert.IsFalse(((WithoutFirstNumberAssigned)11).IsValid());
        Assert.IsFalse(((WithoutFirstNumberAssigned)6).IsValid());
        Assert.IsFalse(((WithoutFirstNumberAssigned)(7 | 9)).IsValid());
        Assert.IsFalse(((WithoutFirstNumberAssigned)(8 + 10)).IsValid());

        Assert.IsTrue(((WithNagativeNumbers)(-7)).IsValid());
        Assert.IsTrue(((WithNagativeNumbers)(-8)).IsValid());
        Assert.IsTrue(((WithNagativeNumbers)(-9)).IsValid());
        Assert.IsTrue(((WithNagativeNumbers)(-10)).IsValid());
        Assert.IsFalse(((WithNagativeNumbers)(-11)).IsValid());
        Assert.IsFalse(((WithNagativeNumbers)(7)).IsValid());
        Assert.IsFalse(((WithNagativeNumbers)(8)).IsValid());
    }
}

1
এর জন্য ধন্যবাদ, আমার বৈধ পতাকা সংমিশ্রণের সাথে সম্পর্কিত একই ধরণের সমস্যা হয়েছিল। এনামের প্রথম চরিত্রটি পরীক্ষা করার বিকল্প হিসাবে, আপনি int.TryParse (enumValue.ToString ()) করার চেষ্টাও করতে পারেন ... এটি যদি ব্যর্থ হয় তবে আপনার কাছে পতাকাগুলির একটি বৈধ সেট রয়েছে। যদিও এটি আপনার সমাধানের চেয়ে ধীর হতে পারে।
ম্যাডহেনচবট

এই প্রয়োগটি সঠিকভাবে নেতিবাচক মানগুলিকে বৈধ করতে ব্যর্থ হয়েছে, যেহেতু চেকটি অ-অঙ্কের অক্ষরের জন্য
চেসমেড্যালিয়ন

ভালো বল ধরা!! আমি আমার উত্তরটি এর সাথে সামঞ্জস্য করে আপডেট করব, ধন্যবাদ @ চেসেমেডালিয়ন
জোশকলে

আমি এই সমাধানটি সবচেয়ে ভাল পছন্দ করি, গণিতের কৌশলগুলি উপস্থাপিত হয় যদি কেবল [Flags]বুদ্ধিমান পূর্ণসংখ্যার মান থাকে।
মিঃলোর

17

ক্যানোনিকাল উত্তর হবে Enum.IsDefined, কিন্তু এটি একটি: একটি [Flags]টান লুপ ব্যবহার করা হলে কিছুটা ধীরে ধীরে এবং খ: এনামগুলির জন্য কার্যকর নয় ।

ব্যক্তিগতভাবে, আমি সে সম্পর্কে উদ্বিগ্ন হওয়া ছেড়ে দেব এবং switchযথাযথভাবে স্মরণ করে:

  • যদি সমস্ত কিছু না সনাক্ত করা ঠিক হয় (এবং কেবল কিছু না করে), তবে একটি যুক্ত করবেন না default:(বা default:কেন একটি ফাঁকা কারণ ব্যাখ্যা করবেন)
  • যদি কোনও বুদ্ধিমান ডিফল্ট আচরণ থাকে, তবে এটিতে রাখুন default:
  • অন্যথায়, আপনি যা জানেন সেগুলি পরিচালনা করুন এবং বাকিগুলির জন্য একটি ব্যতিক্রম নিক্ষেপ করুন:

তাই ভালো:

switch(someflag) {
    case TriBool.Yes:
        DoSomething();
        break;
    case TriBool.No:
        DoSomethingElse();
        break;
    case TriBool.FileNotFound:
        DoSomethingOther();
        break;
    default:
        throw new ArgumentOutOfRangeException("someflag");
}

[পতাকা] এনামগুলির সাথে পরিচিত নয় এবং পারফরম্যান্স কোনও সমস্যা নয় তাই আপনার উত্তরটি মনে হচ্ছে এনামগুলি প্রথম স্থানে কেন আবিষ্কার হয়েছিল;) আপনার "পয়েন্টগুলি" বা যা কিছু বলা হচ্ছে তাই দেখে আপনার সেখানে বক্তব্য রাখতে হবে । বাজি আপনি এগুলি কিছুই পান নি, তবে কনফিগার ফাইলটি পড়ার পরিস্থিতি সম্পর্কে ভাবুন যেখানে এক শত্রুতে 257 মান রয়েছে। কয়েক ডজন অন্যান্য এনামকে ছেড়ে দিন। প্রচুর কেস-সারি থাকবে ...
চর এম

@ মট্টি - এটি চরম উদাহরণ বলে মনে হচ্ছে; deserialization যাইহোক একটি বিশেষজ্ঞ ক্ষেত্র - বেশিরভাগ সিরিয়ালাইজেশন ইঞ্জিনগুলি নিখরচায় এনাম বৈধতা দেয়।
মার্ক Gravell

@ মট্টি - একদিকে নোটে; আমি তাদের পৃথক যোগ্যতার ভিত্তিতে উত্তরগুলি ট্রিট করতে বলব। আমি মাঝে মাঝে জিনিসগুলি সম্পূর্ণরূপে ভুল হয়ে যায়, এবং "প্রতিনিধি 17" সহ কেউ ঠিক ততটাই সমান একটি সঠিক উত্তর দিতে পারে।
মার্ক Gravell

স্যুইচ উত্তরটি দ্রুত, তবে জেনেরিক নয়।
এল্ড্রিচ কনড্রাম

8

ব্যবহার করুন:

Enum.IsDefined ( typeof ( Enum ), EnumValue );


4

আপনার সাথে ডিল করার জন্য সি # কুকবুক থেকেও এই সমাধানটি[Flags] ব্যবহার করতে পারেন :

প্রথমে ALLআপনার এনামে একটি নতুন মান যুক্ত করুন :

[Flags]
enum Language
{
    CSharp = 1, VBNET = 2, VB6 = 4, 
    All = (CSharp | VBNET | VB6)
}

তারপরে, মানটি কিনা তা পরীক্ষা করুন ALL:

public bool HandleFlagsEnum(Language language)
{
    if ((language & Language.All) == language)
    {
        return (true);
    }
    else
    {
        return (false);
    }
}

2

করার এক উপায় হ'ল কাস্টিংয়ের উপর নির্ভর করা এবং স্ট্রিং রূপান্তরটিতে এনাম। যখন এনাম টাইপ করার সময় এনাম টাইপ করা হয় তা হয় প্রাসঙ্গিকভাবে এনামের সাথে রূপান্তরিত হয় অথবা ফলস্বরূপ এনুমের মান হিসাবে অন্তর্গত থাকে যদি এনামের মানটির জন্য সংজ্ঞা না দেওয়া হয়।

enum NetworkStatus{
  Unknown=0,
  Active,
  Slow
}

int statusCode=2;
NetworkStatus netStatus = (NetworkStatus) statusCode;
bool isDefined = netStatus.ToString() != statusCode.ToString();

কোনও প্রান্তের ক্ষেত্রে পরীক্ষা করা হয়নি।


1

অন্যরা যেমন বলেছে, আপনার কাছে সজ্জিত এনামের জন্য বিট পতাকাগুলির বৈধ সংমিশ্রণ থাকলেও Enum.IsDefinedফিরে আসেfalseFlagsAttribute

দুঃখের বিষয়, বৈধ বিট পতাকাগুলির জন্য সত্য ফিরে আসা পদ্ধতি তৈরির একমাত্র উপায় হ'ল কিছুটা দীর্ঘ:

public static bool ValidateEnumValue<T>(T value) where T : Enum
{
    // Check if a simple value is defined in the enum.
    Type enumType = typeof(T);
    bool valid = Enum.IsDefined(enumType, value);
    // For enums decorated with the FlagsAttribute, allow sets of flags.
    if (!valid && enumType.GetCustomAttributes(typeof(FlagsAttribute), false)?.Any() == true)
    {
        long mask = 0;
        foreach (object definedValue in Enum.GetValues(enumType))
            mask |= Convert.ToInt64(definedValue);
        long longValue = Convert.ToInt64(value);
        valid = (mask & longValue) == longValue;
    }
    return valid;
}

আপনি GetCustomAttributeকোনও অভিধানে ফলাফলগুলি ক্যাশে করতে চাইতে পারেন :

private static readonly Dictionary<Type, bool> _flagEnums = new Dictionary<Type, bool>();
public static bool ValidateEnumValue<T>(T value) where T : Enum
{
    // Check if a simple value is defined in the enum.
    Type enumType = typeof(T);
    bool valid = Enum.IsDefined(enumType, value);
    if (!valid)
    {
        // For enums decorated with the FlagsAttribute, allow sets of flags.
        if (!_flagEnums.TryGetValue(enumType, out bool isFlag))
        {
            isFlag = enumType.GetCustomAttributes(typeof(FlagsAttribute), false)?.Any() == true;
            _flagEnums.Add(enumType, isFlag);
        }
        if (isFlag)
        {
            long mask = 0;
            foreach (object definedValue in Enum.GetValues(enumType))
                mask |= Convert.ToInt64(definedValue);
            long longValue = Convert.ToInt64(value);
            valid = (mask & longValue) == longValue;
        }
    }
    return valid;
}

নোট করুন যে উপরের কোডটি নতুন Enumসীমাবদ্ধতা ব্যবহার করে Tযার উপর কেবল সি # 7.3 রয়েছে available আপনাকে object valueপুরানো সংস্করণগুলিতে একটি পাস করতে হবে এবং GetType()এটিতে কল করতে হবে।

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