আমরা কি সি # তে এনামগুলির অন্তর্নিহিত রূপান্তরগুলি সংজ্ঞায়িত করতে পারি?


129

সি # তে এনামগুলির অন্তর্নিহিত রূপান্তর সংজ্ঞা দেওয়া সম্ভব?

এই অর্জন করতে পারে যে কিছু?

public enum MyEnum
{
    one = 1, two = 2
}

MyEnum number = MyEnum.one;
long i = number;

তা না হলে কেন?


2
আমিও এটি করতে চাই আমাদের এমন একটি এনাম রয়েছে enum YesNo {Yes, No}যা স্পষ্টভাবে বিলে রূপান্তর করতে পারে।
কর্নেল আতঙ্ক

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

লিঙ্কটি আর বৈধ নয় - আমরা হয় লিঙ্কটি সরিয়ে ফেলতে পারি, বা ওয়েবসাইটটি কোথাও আবার পোস্ট করতে পারি?
イ き ん ぐ

উত্তর:


128

একটি সমাধান আছে। নিম্নোক্ত বিবেচনা কর:

public sealed class AccountStatus
{
    public static readonly AccountStatus Open = new AccountStatus(1);
    public static readonly AccountStatus Closed = new AccountStatus(2);

    public static readonly SortedList<byte, AccountStatus> Values = new SortedList<byte, AccountStatus>();
    private readonly byte Value;

    private AccountStatus(byte value)
    {
        this.Value = value;
        Values.Add(value, this);
    }


    public static implicit operator AccountStatus(byte value)
    {
        return Values[value];
    }

    public static implicit operator byte(AccountStatus value)
    {
        return value.Value;
    }
}

উপরেরগুলি অন্তর্নিহিত রূপান্তর প্রস্তাব:

        AccountStatus openedAccount = 1;            // Works
        byte openedValue = AccountStatus.Open;      // Works

এটি একটি সাধারণ এনাম ঘোষণার চেয়ে মোটামুটি কাজ (যদিও আপনি উপরের কিছুটিকে সাধারণ জেনেরিক বেস শ্রেণিতে পরিণত করতে পারেন)। বেস ক্লাসটি আইকাম্পারেবল এবং আইকোয়েটেবল বাস্তবায়ন করার পাশাপাশি বর্ণনাঅ্যাট্রিবিউটস, ঘোষিত নাম ইত্যাদি ইত্যাদির মান ফিরিয়ে দেওয়ার জন্য পদ্ধতি যুক্ত করে আপনি আরও এগিয়ে যেতে পারেন

আমি বেশিরভাগ গ্রান্ট কাজ পরিচালনা করতে একটি বেস ক্লাস (রিচএনাম <>) লিখেছি, যা এনামগুলির উপরের ঘোষণাকে নীচে নামিয়ে দেয়:

public sealed class AccountStatus : RichEnum<byte, AccountStatus>
{
    public static readonly AccountStatus Open = new AccountStatus(1);
    public static readonly AccountStatus Closed = new AccountStatus(2);

    private AccountStatus(byte value) : base (value)
    {
    }

    public static implicit operator AccountStatus(byte value)
    {
        return Convert(value);
    }
}

বেস ক্লাস (রিচইনাম) নীচে তালিকাভুক্ত করা হয়েছে।

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;

namespace Ethica
{
    using Reflection;
    using Text;

    [DebuggerDisplay("{Value} ({Name})")]
    public abstract class RichEnum<TValue, TDerived>
                : IEquatable<TDerived>,
                  IComparable<TDerived>,
                  IComparable, IComparer<TDerived>
        where TValue : struct , IComparable<TValue>, IEquatable<TValue>
        where TDerived : RichEnum<TValue, TDerived>
    {
        #region Backing Fields

        /// <summary>
        /// The value of the enum item
        /// </summary>
        public readonly TValue Value;

        /// <summary>
        /// The public field name, determined from reflection
        /// </summary>
        private string _name;

        /// <summary>
        /// The DescriptionAttribute, if any, linked to the declaring field
        /// </summary>
        private DescriptionAttribute _descriptionAttribute;

        /// <summary>
        /// Reverse lookup to convert values back to local instances
        /// </summary>
        private static SortedList<TValue, TDerived> _values;

        private static bool _isInitialized;


        #endregion

        #region Constructors

        protected RichEnum(TValue value)
        {
            if (_values == null)
                _values = new SortedList<TValue, TDerived>();
            this.Value = value;
            _values.Add(value, (TDerived)this);
        }

        #endregion

        #region Properties

        public string Name
        {
            get
            {
                CheckInitialized();
                return _name;
            }
        }

        public string Description
        {
            get
            {
                CheckInitialized();

                if (_descriptionAttribute != null)
                    return _descriptionAttribute.Description;

                return _name;
            }
        }

        #endregion

        #region Initialization

        private static void CheckInitialized()
        {
            if (!_isInitialized)
            {
                ResourceManager _resources = new ResourceManager(typeof(TDerived).Name, typeof(TDerived).Assembly);

                var fields = typeof(TDerived)
                                .GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public)
                                .Where(t => t.FieldType == typeof(TDerived));

                foreach (var field in fields)
                {

                    TDerived instance = (TDerived)field.GetValue(null);
                    instance._name = field.Name;
                    instance._descriptionAttribute = field.GetAttribute<DescriptionAttribute>();

                    var displayName = field.Name.ToPhrase();
                }
                _isInitialized = true;
            }
        }

        #endregion

        #region Conversion and Equality

        public static TDerived Convert(TValue value)
        {
            return _values[value];
        }

        public static bool TryConvert(TValue value, out TDerived result)
        {
            return _values.TryGetValue(value, out result);
        }

        public static implicit operator TValue(RichEnum<TValue, TDerived> value)
        {
            return value.Value;
        }

        public static implicit operator RichEnum<TValue, TDerived>(TValue value)
        {
            return _values[value];
        }

        public static implicit operator TDerived(RichEnum<TValue, TDerived> value)
        {
            return value;
        }

        public override string ToString()
        {
            return _name;
        }

        #endregion

        #region IEquatable<TDerived> Members

        public override bool Equals(object obj)
        {
            if (obj != null)
            {
                if (obj is TValue)
                    return Value.Equals((TValue)obj);

                if (obj is TDerived)
                    return Value.Equals(((TDerived)obj).Value);
            }
            return false;
        }

        bool IEquatable<TDerived>.Equals(TDerived other)
        {
            return Value.Equals(other.Value);
        }


        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }

        #endregion

        #region IComparable Members

        int IComparable<TDerived>.CompareTo(TDerived other)
        {
            return Value.CompareTo(other.Value);
        }

        int IComparable.CompareTo(object obj)
        {
            if (obj != null)
            {
                if (obj is TValue)
                    return Value.CompareTo((TValue)obj);

                if (obj is TDerived)
                    return Value.CompareTo(((TDerived)obj).Value);
            }
            return -1;
        }

        int IComparer<TDerived>.Compare(TDerived x, TDerived y)
        {
            return (x == null) ? -1 :
                   (y == null) ? 1 :
                    x.Value.CompareTo(y.Value);
        }

        #endregion

        public static IEnumerable<TDerived> Values
        {
            get
            {
                return _values.Values;
            }
        }

        public static TDerived Parse(string name)
        {
            foreach (TDerived value in _values.Values)
                if (0 == string.Compare(value.Name, name, true) || 0 == string.Compare(value.DisplayName, name, true))
                    return value;

            return null;
        }
    }
}

পোস্টে একটি সামান্য অফগার্ড ত্রুটি সংশোধন করা হয়েছে :-) এটি সর্বজনীন স্ট্যাটিক ইম্পিলিটেড অপারেটর অ্যাকাউন্টস্ট্যাটাস (বাইট মান) {রিভার্ট কনভার্ট (মান); Con রূপান্তর (বাইট) ফেরত না;
মেহেদী লামরানি

আমি এই বেসক্লাস সংকলন করেছি। আমি যদি পরিবর্তনগুলিতে সম্পাদনা করি তবে আপনি কি আপত্তি করেন?
শেে

64
এই সমাধানটি অনুশীলন হিসাবে 'সঠিক' হতে পারে, বা কারও প্রোগ্রামিং দক্ষতা পরীক্ষা করতে পারে তবে দয়া করে, বাস্তব জীবনে এটি করবেন না। এটি কেবল অতিমাত্রায় নয়, এটি উত্পাদনহীন, অকল্পনীয় এবং জাহান্নাম হিসাবে কুরুচিপূর্ণ। এটির প্রয়োজনে আপনার কোনও এনাম ব্যবহার করার দরকার নেই। আপনি হয় একটি সুস্পষ্ট কাস্ট লাগিয়েছেন বা কেবল কনস্ট ইনটগুলি সহ একটি স্ট্যাটিক ক্লাস লিখেছেন।
8:58

3
এটি মূলত জাভা এনাম পুনরায় প্রয়োগ করা হয় না?
এজেন্ট_এল

2
একটি বড় সমস্যা হ'ল আপনি সেই স্ট্যাটিক রিডোনলি কনস্ট্যান্টগুলি স্যুইচ স্টেটমেন্টগুলিতে ব্যবহার করতে পারবেন না।
আয়ান গোল্ডবি

34

আপনি জড়িত রূপান্তরগুলি (শূন্য বাদে) করতে পারবেন না এবং আপনি নিজের উদাহরণ পদ্ধতিগুলি লিখতে পারবেন না - তবে আপনি সম্ভবত নিজের এক্সটেনশন পদ্ধতিগুলি লিখতে পারেন:

public enum MyEnum { A, B, C }
public static class MyEnumExt
{
    public static int Value(this MyEnum foo) { return (int)foo; }
    static void Main()
    {
        MyEnum val = MyEnum.A;
        int i = val.Value();
    }
}

এটি আপনাকে অনেক কিছু দেয় না, যদিও (কেবলমাত্র একটি স্পষ্ট অভিনেতার তুলনায়)।

লোকেদের [Flags]এটির যে প্রধান সময় আমি দেখেছি তার মধ্যে একটি হ'ল জেনেরিকের মাধ্যমে হেরফের করা - অর্থাত্ একটি bool IsFlagSet<T>(T value, T flag);পদ্ধতি। দুর্ভাগ্যক্রমে, সি # 3.0 জেনারিকগুলিতে অপারেটরদের সমর্থন করে না, তবে আপনি এই জাতীয় জিনিসগুলি ব্যবহার করে এটি পেতে পারেন যা অপারেটরদের জেনেরিকের সাথে পুরোপুরি উপলব্ধ করে তোলে।


হ্যাঁ, এটি সি # 4 এর জন্য আমার অন্যতম পছন্দ ছিল: স্ট্যাকওভারফ্লো / সিকিউশনস
কীথ

@ কিথ - ভাল কাজ এটি তৈরি করেছে, তারপরে ;- গতিশীল / অপারেটর সমর্থন এটি সিটিপিতে তৈরি করতে পারেনি, তবে গতিশীল সাথে অপারেটরগুলির জন্য দুটি পদ্ধতির তুলনা করার জন্য আমি একটি পরীক্ষার জন্য প্রস্তুত রোল পেয়েছি ( বনাম জেনেরিকস / এক্সপ্রেশন) যখন সেখানে আসে।
মার্ক গ্র্যাভেল

@ কিথ - আপনি মিসকিল-এ অপারেটর ক্লাস দিতে পারেন; আমি নিশ্চিত যে এটি আপনি যা চান তা বেশিরভাগই করবে।
মার্ক গ্র্যাভেল

22
struct PseudoEnum
{
    public const int 
              INPT = 0,
              CTXT = 1,
              OUTP = 2;
};

// ...

var arr = new String[3];

arr[PseudoEnum.CTXT] = "can";
arr[PseudoEnum.INPT] = "use";
arr[PseudoEnum.CTXT] = "as";
arr[PseudoEnum.CTXT] = "array";
arr[PseudoEnum.OUTP] = "index";

তবে স্ট্রাক্ট কেন?
কনরাড

1
আসলে কোন কারণ নেই। static classআমি মনে করি আপনি ব্যবহার করতে পারেন । চূড়ান্ত ILকোডে উভয় ক্ষেত্রেই তর্ক করার কোনও সুবিধা নেই ।
গ্লেন স্লেডেন

18

আমি মার্কের দুর্দান্ত রিচএনম জেনেরিক বেসক্লাসটি অভিযোজিত করেছি।

স্থাপন করা

  1. তাঁর গ্রন্থাগারগুলি থেকে বিটগুলি হারিয়ে যাওয়ার কারণে সংকলন সংক্রান্ত বেশ কয়েকটি সমস্যা (উল্লেখযোগ্যভাবে: সংস্থান নির্ভর নির্ভর নামগুলি পুরোপুরি সরানো হয়নি; তারা এখন)
  2. সূচনাটি নিখুঁত ছিল না: যদি আপনি প্রথম কাজটি করেন তবে স্থির অ্যাক্সেস করা হত from বেস শ্রেণি থেকে সম্পত্তি মূল্য, আপনি একটি এনপিই পেতে পারেন। বেস ক্লাসটি কৌতূহলী-পুনরাবৃত্তভাবে ( সিআরটিপি) জোর করে এটি স্থির করে CheckInitialized সময়ে) ঠিক সময়ে TDerived স্ট্যাটিক নির্মাণ বাধ্য
  3. অবশেষে চেক ইনিশিয়ালাইজড লজিককে একটি স্ট্যাটিক কনস্ট্রাক্টরে সরানো হয়েছে (প্রতিবারের চেকিংয়ের শাস্তি এড়াতে মাল্টিথ্রেডেড ইনিশিয়েশনের উপর দৌড় শর্ত; সম্ভবত এটি আমার বুলেট ১ দ্বারা সমাধান করা একটি অসম্ভবতা ছিল?)

দুর্দান্ত ধারণা + বাস্তবায়নের জন্য কুডোসকে চিহ্নিত করুন, আপনার সকলের জন্য এখানে:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Resources;

namespace NMatrix
{

    [DebuggerDisplay("{Value} ({Name})")]
    public abstract class RichEnum<TValue, TDerived>
                : IEquatable<TDerived>,
                  IComparable<TDerived>,
                  IComparable, IComparer<TDerived>
        where TValue : struct, IComparable<TValue>, IEquatable<TValue>
        where TDerived : RichEnum<TValue, TDerived>
    {
        #region Backing Fields

        /// <summary>
        /// The value of the enum item
        /// </summary>
        public readonly TValue Value;

        /// <summary>
        /// The public field name, determined from reflection
        /// </summary>
        private string _name;

        /// <summary>
        /// The DescriptionAttribute, if any, linked to the declaring field
        /// </summary>
        private DescriptionAttribute _descriptionAttribute;

        /// <summary>
        /// Reverse lookup to convert values back to local instances
        /// </summary>
        private static readonly SortedList<TValue, TDerived> _values = new SortedList<TValue, TDerived>();

        #endregion

        #region Constructors

        protected RichEnum(TValue value)
        {
            this.Value = value;
            _values.Add(value, (TDerived)this);
        }

        #endregion

        #region Properties

        public string Name
        {
            get
            {
                return _name;
            }
        }

        public string Description
        {
            get
            {
                if (_descriptionAttribute != null)
                    return _descriptionAttribute.Description;

                return _name;
            }
        }

        #endregion

        #region Initialization

        static RichEnum()
        {
            var fields = typeof(TDerived)
                .GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public)
                .Where(t => t.FieldType == typeof(TDerived));

            foreach (var field in fields)
            {
                /*var dummy =*/ field.GetValue(null); // forces static initializer to run for TDerived

                TDerived instance = (TDerived)field.GetValue(null);
                instance._name = field.Name;
                                    instance._descriptionAttribute = field.GetCustomAttributes(true).OfType<DescriptionAttribute>().FirstOrDefault();
            }
        }

        #endregion

        #region Conversion and Equality

        public static TDerived Convert(TValue value)
        {
            return _values[value];
        }

        public static bool TryConvert(TValue value, out TDerived result)
        {
            return _values.TryGetValue(value, out result);
        }

        public static implicit operator TValue(RichEnum<TValue, TDerived> value)
        {
            return value.Value;
        }

        public static implicit operator RichEnum<TValue, TDerived>(TValue value)
        {
            return _values[value];
        }

        public static implicit operator TDerived(RichEnum<TValue, TDerived> value)
        {
            return value;
        }

        public override string ToString()
        {
            return _name;
        }

        #endregion

        #region IEquatable<TDerived> Members

        public override bool Equals(object obj)
        {
            if (obj != null)
            {
                if (obj is TValue)
                    return Value.Equals((TValue)obj);

                if (obj is TDerived)
                    return Value.Equals(((TDerived)obj).Value);
            }
            return false;
        }

        bool IEquatable<TDerived>.Equals(TDerived other)
        {
            return Value.Equals(other.Value);
        }


        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }

        #endregion

        #region IComparable Members

        int IComparable<TDerived>.CompareTo(TDerived other)
        {
            return Value.CompareTo(other.Value);
        }

        int IComparable.CompareTo(object obj)
        {
            if (obj != null)
            {
                if (obj is TValue)
                    return Value.CompareTo((TValue)obj);

                if (obj is TDerived)
                    return Value.CompareTo(((TDerived)obj).Value);
            }
            return -1;
        }

        int IComparer<TDerived>.Compare(TDerived x, TDerived y)
        {
            return (x == null) ? -1 :
                   (y == null) ? 1 :
                    x.Value.CompareTo(y.Value);
        }

        #endregion

        public static IEnumerable<TDerived> Values
        {
            get
            {
                return _values.Values;
            }
        }

        public static TDerived Parse(string name)
        {
            foreach (TDerived value in Values)
                if (0 == string.Compare(value.Name, name, true))
                    return value;

            return null;
        }
    }
}

ব্যবহারের নমুনা যা আমি মনোতে চালিয়েছি:

using System.ComponentModel;
using System;

namespace NMatrix
{    
    public sealed class MyEnum : RichEnum<int, MyEnum>
    {
        [Description("aap")]  public static readonly MyEnum my_aap   = new MyEnum(63000);
        [Description("noot")] public static readonly MyEnum my_noot  = new MyEnum(63001);
        [Description("mies")] public static readonly MyEnum my_mies  = new MyEnum(63002);

        private MyEnum(int value) : base (value) { } 
        public static implicit operator MyEnum(int value) { return Convert(value); }
    }

    public static class Program
    {
        public static void Main(string[] args)
        {
            foreach (var enumvalue in MyEnum.Values)
                Console.WriteLine("MyEnum {0}: {1} ({2})", (int) enumvalue, enumvalue, enumvalue.Description);
        }
    }
}

আউটপুট উত্পাদন

[mono] ~/custom/demo @ gmcs test.cs richenum.cs && ./test.exe 
MyEnum 63000: my_aap (aap)
MyEnum 63001: my_noot (noot)
MyEnum 63002: my_mies (mies)

দ্রষ্টব্য: মনো 2.6.7 এর জন্য অতিরিক্ত সুস্পষ্ট কাস্ট প্রয়োজন যা মোनो 2.8.2 ব্যবহার করার সময় প্রয়োজন হয় না ...


বর্ণনা বিশিষ্টতা পেতে .Single () ব্যবহার করা ভাল ধারণা নয়। যদি কোনও বৈশিষ্ট্য না থাকে, তবে সিঙ্গল () একটি ব্যতিক্রম ছুঁড়ে দেয়, সিঙ্গেলঅরডিফল্ট () দেয় না।
কেরেম

@ কেরেম ভাল পয়েন্ট, আমি এটি আপডেট করেছি (ব্যবহার করে FirstOrDefault, কেবলমাত্র একটি একক বৈশিষ্ট্য আছে তা ধরে রাখতে)। এই জাতীয় বিষয়গুলি ধরে নেওয়া বা না করা 'একটি ভাল ধারণা' (বা
এটির

1
এটি পছন্দ করুন, তবে আমি একটি সমস্যায় পড়েছিলাম: উইন্ডোজ 7 /। নেট 4.4 এ এই লাইনটি TDerived instance = (TDerived)field.GetValue(null);ফলাফল instanceহিসাবে আসে null। দেখে মনে হচ্ছে মনো মনো রানটাইমের অবশ্যই .NET এর চেয়ে টাইপ ইনিশিয়ালাইজের আলাদা অর্ডার থাকতে হবে যা এটি কাজ করতে দেয়। বিরক্তিকর! পরিবর্তে আমাকে সেই কোডটি একটি স্ট্যাটিক পদ্ধতিতে স্থানান্তরিত করে সাবক্লাসের টাইপ ইনিশিয়ালাইজার থেকে কল করতে হয়েছিল।
এজেন্টেগা

@agentnega যোগ করার জন্য ধন্যবাদ এটি কারও সাহায্য করতে পারে।
শেহে

@ এজেন্টেগা। নেট .৪.৪.১ এ আমি একই সমস্যাটি অনুভব করছি। মনে হয় এটি সি # স্পেসিফিকেশনকে "লঙ্ঘন" করেছে / সি এটি প্রথম ব্যবহারের আগে মানটি আরম্ভ করে না - কমপক্ষে প্রতিফলন ব্যবহার করার সময় নয়। আমি এমন একটি বাস্তবায়ন বাস্তবায়িত করেছি যার সাথে সাবক্লাসের ('টিডিরিভড') জড়িত থাকতে হবে না। @ সেহে আমি কি আপনার উত্তরটি সম্পাদনা করে আপনার উত্তরে কাজটি যুক্ত করব বা আমার একটি নতুন উত্তর পোস্ট করা উচিত?
ব্যাটারিব্যাকআপ ইউনিট

5

আপনি এনাম ধরণের ক্ষেত্রে অন্তর্নিহিত রূপান্তরগুলি ঘোষণা করতে পারবেন না, কারণ তারা পদ্ধতিগুলি নির্ধারণ করতে পারে না। সি # অন্তর্নিহিত কীওয়ার্ডটি 'op_' দিয়ে শুরু করে একটি পদ্ধতিতে সংকলিত হয় এবং এটি এই ক্ষেত্রে কাজ করবে না।


4

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

public class MyClass {

    public static implicit operator MyClass ( MyEnum input ) {
        //...
    }
}

MyClass m = MyEnum.One;

প্রশ্ন হবে কেন?

সাধারণভাবে। নেট কোনওরকম অন্তর্নিহিত রূপান্তর এড়িয়ে চলে (এবং আপনারও উচিত) যেখানে ডেটা নষ্ট হতে পারে।


3

আপনি যদি এনামের বেসটিকে দীর্ঘ হিসাবে সংজ্ঞায়িত করেন তবে আপনি সুস্পষ্ট রূপান্তর সম্পাদন করতে পারেন। আমি জানি না যে আপনি অন্তর্নিহিত রূপান্তরগুলি ব্যবহার করতে পারেন কারণ এনামগুলিতে তাদের কোনও পদ্ধতি নির্ধারণ করা যায় না cannot

public enum MyEnum : long
{
    one = 1,
    two = 2,
}

MyEnum number = MyEnum.one;
long i = (long)number;

এছাড়াও, এটির সাথে সচেতন থাকুন যে একটি অবিচ্ছিন্ন গণনা 0 মান বা প্রথম আইটেমটিতে ডিফল্ট হবে - সুতরাং উপরের পরিস্থিতিতে সম্ভবত এটিও সংজ্ঞা zero = 0দেওয়া ভাল best


5
তোমার : longএখানে দরকার নেই; সুস্পষ্ট রূপান্তর এটিকে ছাড়াই সূক্ষ্মভাবে কাজ করবে। একমাত্র আইনী অন্তর্নিহিত রূপান্তরটি শূন্য।
মার্ক গ্র্যাভেল

3
না; ডিফল্ট এনামটি হল ইন্টার 32
মার্ক গ্র্যাভেল

1
দেখুন: এনাম ফু {এ, বি, সি} কনসোল.ওরাইটলাইন (এনাম.গেটউন্ডারিলিং টাইপ (টাইপফ (ফু)));
মার্ক গ্র্যাভেল

14
কেন এটি উত্তর হিসাবে চিহ্নিত হয়েছে এবং এতগুলি পয়েন্ট রয়েছে? এটি ওপি প্রশ্নের সাথে প্রাসঙ্গিক নয় !!! তিনি IMPLICIT রূপান্তর সম্পর্কে কথা বলছেন ... যুক্ত হওয়া মূল্য শূন্য।
মেহেদী লামরানী

3
প্রশ্নটি ইতিমধ্যে ইঙ্গিত দেয় যে সুস্পষ্ট কাস্টগুলি বোঝা যায়, প্রশ্নটি "আমি কীভাবে স্পষ্টভাবে কাস্টিং এড়াতে পারি?" জিজ্ঞাসার সমতুল্য, এই পোস্টটি প্রয়োগ হয় না।
কিট 10

2

এনপিগুলি এ কারণে আমার পক্ষে অনেকাংশে অকেজো OP

আমি পিক-সম্পর্কিত সব সময় শেষ করি:

সহজ সমাধান

ক্লাসিক উদাহরণ সমস্যাটি হ'ল কীপ্রেসগুলি সনাক্ত করার জন্য ভার্চুয়ালকি সেট।

enum VKeys : ushort
{
a = 1,
b = 2,
c = 3
}
// the goal is to index the array using predefined constants
int[] array = new int[500];
var x = array[VKeys.VK_LSHIFT]; 

এখানে সমস্যাটি হ'ল আপনি এনামের সাথে অ্যারের সূচী করতে পারবেন না কারণ এটি স্পষ্টভাবে এনামকে ইউএস্টে রূপান্তর করতে পারে না (যদিও আমরা এমনকি এনামকে ইউএস্টের উপর ভিত্তি করে)

এই নির্দিষ্ট প্রসঙ্গে এনামগুলি নিম্নলিখিত ডেটাস্ট্রাকচার দ্বারা অপ্রচলিত। । । ।

public static class VKeys
{
public const ushort
a = 1,
b = 2, 
c = 3;
}

1

এমএস। নেট (নন-মনো) তে কোড চালানোর সময় আমি সেহের উত্তর নিয়ে একটি সমস্যা নিয়ে কাজ করেছি । আমার জন্য বিশেষত সমস্যাটি নেট .৪.৪.১ এ এসেছিল তবে অন্যান্য সংস্করণগুলিও এটি প্রভাবিত বলে মনে হচ্ছে।

সমস্যাটি

public static TDervied MyEnumValueপ্রতিবিম্ব দ্বারা একটি অ্যাক্সেস (মাধ্যমে ক্ষেত্রের সূচনা FieldInfo.GetValue(null)হয় না

কর্মক্ষেত্রের

TDerivedএর স্থায়ী ইনিশিয়ালাইজারের উপর উদাহরণগুলিতে নাম দেওয়ার পরিবর্তে RichEnum<TValue, TDerived>প্রথম অ্যাক্সেসে অলসভাবে সম্পন্ন করা হয় TDerived.Name। কোড:

public abstract class RichEnum<TValue, TDerived> : EquatableBase<TDerived>
    where TValue : struct, IComparable<TValue>, IEquatable<TValue>
    where TDerived : RichEnum<TValue, TDerived>
{
    // Enforcing that the field Name (´SomeEnum.SomeEnumValue´) is the same as its 
    // instances ´SomeEnum.Name´ is done by the static initializer of this class.
    // Explanation of initialization sequence:
    // 1. the static initializer of ´RichEnum<TValue, TDerived>´ reflects TDervied and 
    //    creates a list of all ´public static TDervied´ fields:
    //   ´EnumInstanceToNameMapping´
    // 2. the static initializer of ´TDerive´d assigns values to these fields
    // 3. The user is now able to access the values of a field.
    //    Upon first access of ´TDervied.Name´ we search the list 
    //    ´EnumInstanceToNameMapping´ (created at step 1) for the field that holds
    //    ´this´ instance of ´TDerived´.
    //    We then get the Name for ´this´ from the FieldInfo
    private static readonly IReadOnlyCollection<EnumInstanceReflectionInfo> 
                            EnumInstanceToNameMapping = 
        typeof(TDerived)
            .GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public)
            .Where(t => t.FieldType == typeof(TDerived))
            .Select(fieldInfo => new EnumInstanceReflectionInfo(fieldInfo))
            .ToList();

    private static readonly SortedList<TValue, TDerived> Values =
        new SortedList<TValue, TDerived>();

    public readonly TValue Value;

    private readonly Lazy<string> _name;

    protected RichEnum(TValue value)
    {
        Value = value;

        // SortedList doesn't allow duplicates so we don't need to do
        // duplicate checking ourselves
        Values.Add(value, (TDerived)this);

        _name = new Lazy<string>(
                    () => EnumInstanceToNameMapping
                         .First(x => ReferenceEquals(this, x.Instance))
                         .Name);
    }

    public string Name
    {
        get { return _name.Value; }
    }

    public static implicit operator TValue(RichEnum<TValue, TDerived> richEnum)
    {
        return richEnum.Value;
    }

    public static TDerived Convert(TValue value)
    {
        return Values[value];
    }

    protected override bool Equals(TDerived other)
    {
        return Value.Equals(other.Value);
    }

    protected override int ComputeHashCode()
    {
        return Value.GetHashCode();
    }

    private class EnumInstanceReflectionInfo
    {
        private readonly FieldInfo _field;
        private readonly Lazy<TDerived> _instance;

        public EnumInstanceReflectionInfo(FieldInfo field)
        {
            _field = field;
            _instance = new Lazy<TDerived>(() => (TDerived)field.GetValue(null));
        }

        public TDerived Instance
        {
            get { return _instance.Value; }
        }

        public string Name { get { return _field.Name; } }
    }
}

যা - আমার ক্ষেত্রে - এর উপর ভিত্তি করে EquatableBase<T>:

public abstract class EquatableBase<T>
    where T : class 
{
    public override bool Equals(object obj)
    {
        if (this == obj)
        {
            return true;
        }

        T other = obj as T;
        if (other == null)
        {
            return false;
        }

        return Equals(other);
    }

    protected abstract bool Equals(T other);

    public override int GetHashCode()
    {
        unchecked
        {
            return ComputeHashCode();
        }
    }

    protected abstract int ComputeHashCode();
}

বিঃদ্রঃ

উপরের কোডটি মার্কের মূল উত্তরটির সমস্ত বৈশিষ্ট্য সংযুক্ত করে না !

ধন্যবাদ

ধন্যবাদ মার্ক তার প্রদানের জন্য RichEnumবাস্তবায়ন ও ধন্যবাদ sehe কিছুটা উন্নতি প্রদানের জন্য!


1

আমি এখান থেকে নেওয়া আরও সহজ সমাধান পেয়েছি /codereview/7566/enum-vs-int-wrapper-struct আমি ভবিষ্যতে কাজ না করে যদি সেই লিঙ্কটি থেকে আমি নীচের কোডটি আটকালাম।

struct Day
{
    readonly int day;

    public static readonly Day Monday = 0;
    public static readonly Day Tuesday = 1;
    public static readonly Day Wednesday = 2;
    public static readonly Day Thursday = 3;
    public static readonly Day Friday = 4;
    public static readonly Day Saturday = 5;
    public static readonly Day Sunday = 6;

    private Day(int day)
    {
        this.day = day;
    }

    public static implicit operator int(Day value)
    {
        return value.day;
    }

    public static implicit operator Day(int value)
    {
        return new Day(value);
    }
}

1

আমি এই ইউটিলিটি সাহায্যের জন্য আমাকে একটি রূপান্তর নির্মিত Enum করার PrimitiveEnum এবং PrimitiveEnum করতে byte, sbyte, short, ushort, int, uint, long, or ulong

সুতরাং, এই প্রযুক্তিগতভাবে কোনও এনামকে তার যে কোনও আদিম মানতে রূপান্তরিত করে।

public enum MyEnum
{
    one = 1, two = 2
}

PrimitiveEnum number = MyEnum.one;
long i = number;

Https://github.com/McKabue/McKabue.Extentions.Utility/blob/master/src/McKabue.Extentions.Utility/Enums/PrimitiveEnum.cs এ প্রতিশ্রুতি দেখুন commit

using System;

namespace McKabue.Extentions.Utility.Enums
{
    /// <summary>
    /// <see href="https://stackoverflow.com/q/261663/3563013">
    /// Can we define implicit conversions of enums in c#?
    /// </see>
    /// </summary>
    public struct PrimitiveEnum
    {
        private Enum _enum;

        public PrimitiveEnum(Enum _enum)
        {
            this._enum = _enum;
        }

        public Enum Enum => _enum;


        public static implicit operator PrimitiveEnum(Enum _enum)
        {
            return new PrimitiveEnum(_enum);
        }

        public static implicit operator Enum(PrimitiveEnum primitiveEnum)
        {
            return primitiveEnum.Enum;
        }

        public static implicit operator byte(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToByte(primitiveEnum.Enum);
        }

        public static implicit operator sbyte(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToSByte(primitiveEnum.Enum);
        }

        public static implicit operator short(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToInt16(primitiveEnum.Enum);
        }

        public static implicit operator ushort(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToUInt16(primitiveEnum.Enum);
        }

        public static implicit operator int(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToInt32(primitiveEnum.Enum);
        }

        public static implicit operator uint(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToUInt32(primitiveEnum.Enum);
        }

        public static implicit operator long(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToInt64(primitiveEnum.Enum);
        }

        public static implicit operator ulong(PrimitiveEnum primitiveEnum)
        {
            return Convert.ToUInt64(primitiveEnum.Enum);
        }
    }
}

+1 আমার কাছে গেমের কাঠামো রয়েছে যা অনেকগুলি দ্বারা শনাক্ত করা হয় uintযা সাধারণত গেমটি নিজেই সাধারণত তৈরি করে enumতবে ফ্রেমওয়ার্কটি কিছুই জানে না। (uint)ফ্রেমওয়ার্কটি কল করার সময় ব্যথা হয়েছিল। আপনার ধারণা পিছনের দিকে নিখুঁতভাবে কাজ করে। পরিবর্তে structসংরক্ষণকারী Enum, আমি একটি আছে struct IdNumberযা সঞ্চয় uintকিন্তু পরোক্ষভাবে ধর্মান্তরিত থেকে Enumখেলা ব্যবহারসমূহ s। ফ্রেমওয়ার্কের প্যারামগুলি uintএগুলি টাইপ করার পরিবর্তে আমি এগুলি টাইপ করতে পারি IdNumberএবং ফ্রেমওয়ার্কটি অভ্যন্তরীণভাবে দক্ষতার সাথে তাদের চারপাশে পাস করতে পারে এমনকি তাদের উপর অবিচ্ছেদ্য অপশনও করে।
কেভিন

-2

এনাম প্রকারের জন্য অন্তর্নিহিত রূপান্তরগুলি প্রকারের সুরক্ষা ভঙ্গ করবে, তাই আমি এটি করার পরামর্শ দিই না। আপনি এটি কেন করতে চান? আমি দেখেছি এটির জন্য একমাত্র ব্যবহারের ক্ষেত্রে আপনি যখন এনাম মানগুলি একটি প্রাক-সংজ্ঞায়িত বিন্যাসের সাথে কোনও কাঠামোতে স্থাপন করতে চান। তবে তারপরেও আপনি কাঠামোতে এনাম টাইপটি ব্যবহার করতে পারেন এবং মার্শালারকে এটি দিয়ে কী করা উচিত তা বলতে পারেন।


এনামগুলির অন্তর্নিহিত রূপান্তরকরণের জন্য আমার একটি ব্যবহার রয়েছে। একই সাইট সংগ্রহের একাধিক সাইটে লাইনকিউ থেকে শেয়ারপয়েন্ট ক্লাস উত্পন্ন করতে এসপিমেটেল ব্যবহার করা। আমার তালিকাগুলির মধ্যে একটি হ'ল একটি সাবসিটে, অন্যরা আলাদা সাবসাইটে। কীভাবে এসপিমেটাল কোড উত্পন্ন করে তার কারণে সংগ্রহের একাধিক তালিকায় ব্যবহৃত সাইট কলামগুলি একাধিক নেমস্পেসে সংজ্ঞায়িত করা যেতে পারে। যাইহোক, আমার পছন্দসই ক্ষেত্রের এনামকে একটি নেমস্পেসের মধ্যে অন্য নেমস্পেসের একই এনামে রূপান্তর করতে হবে। অন্তর্নিহিত রূপান্তর খুব সহায়ক হবে।
Zarepheth
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.