অবৈধ এনাম মানতে কাস্টিং কেন ব্যতিক্রম ছুঁড়ে না?


123

যদি আমার মতো এনাম থাকে:

enum Beer
{
    Bud = 10,
    Stella = 20,
    Unknown
}

intএই মানগুলির বাইরে থাকা কোনও ধরণের মধ্যে castালার সময় কেন এটি ব্যতিক্রম ছুঁড়ে না Beer?

উদাহরণস্বরূপ নিম্নলিখিত কোডটি একটি ব্যতিক্রম ছুঁড়ে না ফেলে, এটি কনসোলে '50' আউটপুট করে:

int i = 50;
var b = (Beer) i;

Console.WriteLine(b.ToString());

আমি এই অদ্ভুত মনে ... কেউ পরিষ্কার করতে পারেন?


27
নোট করুন যে আপনি সর্বদা এনাম.আইএসডিফাইন্ডের সাথে মানটি বৈধ কিনা তা পরীক্ষা করতে পারেন ।
— টিম শ্মেলটার

শীতল আমি এটি জানতাম না, সম্ভবত আমি বর্তমানে যে সমস্যাটি সমাধান করার চেষ্টা করছি তাতে এটি ব্যবহার করবে
— jcvandan


1
বুড়ের চেয়ে দ্বিগুণ দামের স্টেলা তৈরির জন্য উত্সাহিত।
— ড্যান বেচার্ড

উত্তর:


81

এনাম পার্সিংয়ের সাথে বিভ্রান্তি থেকে নেওয়া

নেট। নেট তৈরি করা লোকদের পক্ষ থেকে এটি একটি সিদ্ধান্ত ছিল। একটি enum অন্য মান প্রকার (দ্বারা ব্যাক হয় int, short, byte, ইত্যাদি), এবং তাই এটি আসলে ঐ মান ধরনের জন্য বৈধ কোনো মান থাকতে পারে।

আমি ব্যক্তিগতভাবে এটি যেভাবে কাজ করে তার অনুরাগী নই, তাই আমি বেশ কয়েকটি উপযোগী পদ্ধতি তৈরি করেছি:

/// <summary>
/// Utility methods for enum values. This static type will fail to initialize 
/// (throwing a <see cref="TypeInitializationException"/>) if
/// you try to provide a value that is not an enum.
/// </summary>
/// <typeparam name="T">An enum type. </typeparam>
public static class EnumUtil<T>
    where T : struct, IConvertible // Try to get as much of a static check as we can.
{
    // The .NET framework doesn't provide a compile-checked
    // way to ensure that a type is an enum, so we have to check when the type
    // is statically invoked.
    static EnumUtil()
    {
        // Throw Exception on static initialization if the given type isn't an enum.
        Require.That(typeof (T).IsEnum, () => typeof(T).FullName + " is not an enum type.");
    }

    /// <summary>
    /// In the .NET Framework, objects can be cast to enum values which are not
    /// defined for their type. This method provides a simple fail-fast check
    /// that the enum value is defined, and creates a cast at the same time.
    /// Cast the given value as the given enum type.
    /// Throw an exception if the value is not defined for the given enum type.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="enumValue"></param>
    /// <exception cref="InvalidCastException">
    /// If the given value is not a defined value of the enum type.
    /// </exception>
    /// <returns></returns>
    public static T DefinedCast(object enumValue)

    {
        if (!System.Enum.IsDefined(typeof(T), enumValue))
            throw new InvalidCastException(enumValue + " is not a defined value for enum type " +
                                           typeof (T).FullName);
        return (T) enumValue;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="enumValue"></param>
    /// <returns></returns>
    public static T Parse(string enumValue)
    {
        var parsedValue = (T)System.Enum.Parse(typeof (T), enumValue);
        //Require that the parsed value is defined
        Require.That(parsedValue.IsDefined(), 
            () => new ArgumentException(string.Format("{0} is not a defined value for enum type {1}", 
                enumValue, typeof(T).FullName)));
        return parsedValue;
    }

    public static bool IsDefined(T enumValue)
    {
        return System.Enum.IsDefined(typeof (T), enumValue);
    }

}


public static class EnumExtensions
{
    public static bool IsDefined<T>(this T enumValue)
        where T : struct, IConvertible
    {
        return EnumUtil<T>.IsDefined(enumValue);
    }
}

এইভাবে, আমি বলতে পারি:

if(!sEnum.IsDefined()) throw new Exception(...);

... বা:

EnumUtil<Stooge>.Parse(s); // throws an exception if s is not a defined value.

সম্পাদন করা

উপরে বর্ণিত ব্যাখ্যার বাইরেও আপনাকে বুঝতে হবে যে এনামের .NET সংস্করণটি জাভা-অনুপ্রাণিতের চেয়ে আরও বেশি সি-অনুপ্রাণিত প্যাটার্ন অনুসরণ করে। এটি "বিট পতাকা" এনামগুলি থাকা সম্ভব করে যা কোনও এনাম মানতে নির্দিষ্ট "পতাকা" সক্রিয় কিনা তা নির্ধারণ করতে বাইনারি নিদর্শনগুলি ব্যবহার করতে পারে। আপনি যদি পতাকাগুলির প্রতিটি সম্ভাব্য সংমিশ্রণটি (যেমন MondayAndTuesday, MondayAndWednesdayAndThursday) সংজ্ঞায়িত করতে চান তবে এগুলি অত্যন্ত ক্লান্তিকর হবে। সুতরাং অপরিশোধিত এনাম মানগুলি ব্যবহার করার ক্ষমতা রাখাই সত্যিই সহজ হতে পারে। আপনি যখন এনাম টাইপগুলিতে এই ধরণের কৌশল অবলম্বন না করে একটি ব্যর্থ-দ্রুত আচরণ চান তখন এটির জন্য একটু অতিরিক্ত কাজ প্রয়োজন requires


ভাল ... আমি যেভাবে এটি কাজ করি তার পক্ষে আমি ভক্ত নই, আমার কাছে উদ্ভট মনে হয়
— jcvandan

3
@ ডর্মিশার: "'টিস পাগলামি, তবুও উপায় নেই" " আমার সম্পাদনা দেখুন।
— স্ট্রিপলিং ওয়ারিয়র

2
স্বার্থের জন্য জাভা সমতুল্য EnumSet.of (সোমবার, বুধবার, বৃহস্পতিবার)। এনামসেটের অভ্যন্তরে কেবল একটি দীর্ঘ দীর্ঘ। সুতরাং খুব দক্ষতা ক্ষতি ছাড়াই একটি দুর্দান্ত এপিআই দেয়।
— আইয়েন


আপনার পার্স পদ্ধতিতে @ স্ট্রিপলিং ওয়ারিয়রকে আপনি এক্সটেনশন পদ্ধতির মতো ইসডেফাইন্ড কল করতে চেষ্টা করছেন। তবে আপনি যেভাবে প্রতিবন্ধকতা সহ এনামুটিল ক্লাস করার চেষ্টা করেছেন (এনামের জন্য স্ট্যাটিক চেক করা, যা আমি খুব পছন্দ করি) এর কারণে আইসডিফাইন্ড পদ্ধতিটি একটি এক্সটেনশন পদ্ধতি তৈরি করা যায় না। তবে বাস্তবে এটি আমাকে বলে দিচ্ছে যে কেউ জেনেরিক শ্রেণিতে কোনও এক্সটেনশন পদ্ধতি তৈরি করতে পারে না। কোন ধারনা?
— সিজেসি

55

এনামগুলি প্রায়শই পতাকা হিসাবে ব্যবহৃত হয়:

[Flags]
enum Permission
{
    None = 0x00,
    Read = 0x01,
    Write = 0x02,
}
...

Permission p = Permission.Read | Permission.Write;

পি এর মানটি পূর্ণসংখ্যা 3, যা এনামের মান নয়, তবে স্পষ্টতই একটি বৈধ মান।

আমি ব্যক্তিগতভাবে বরং ভিন্ন সমাধান দেখতে পেতাম; "বিট অ্যারে" পূর্ণসংখ্যার প্রকার এবং "স্বতন্ত্র মানের একটি সেট" প্রকারগুলি উভয়কে "এনাম" এ বিভক্ত করার পরিবর্তে দুটি পৃথক ভাষার বৈশিষ্ট্য হিসাবে তৈরি করার দক্ষতা আমার ছিল । তবে মূল ভাষা এবং কাঠামো ডিজাইনাররা এটাই নিয়ে এসেছিলেন; ফলস্বরূপ, আমাদের এনামের অ-ঘোষিত মানগুলিকে আইনী মান হিসাবে মঞ্জুর করতে হবে।


19
কিন্তু 3 "স্পষ্টতই একটি বৈধ মান" ধরণের ওপির বিষয়টি শক্তিশালী করে। এই [পতাকাগুলি] গুণটি সংকলককে একটি সংজ্ঞায়িত এনুম বা একটি কার্যকর মান সন্ধান করতে পারে। শুধু Sayin'.
— লার্সটেক

15

সংক্ষিপ্ত উত্তর: ভাষা ডিজাইনাররা ভাষাটি এভাবে ডিজাইনের সিদ্ধান্ত নিয়েছিলেন।

দীর্ঘ উত্তর: Section 6.2.2: Explicit enumeration conversionsসি # ভাষার স্পেসিফিকেশন এর বলেছেন:

যে কোনও অংশীদারি এনাম-টাইপকে সেই এনাম-টাইপের অন্তর্নিহিত ধরণের হিসাবে বিবেচনা করে এবং তারপরে ফলাফলগুলির মধ্যে একটি স্পষ্ট বা সংখ্যাসূচক রূপান্তর সম্পাদন করে দুটি ধরণের মধ্যে একটি সুস্পষ্ট গণনা রূপান্তর প্রক্রিয়া করা হয়। উদাহরণস্বরূপ, এনাম-টাইপ ই দেওয়া হয় এবং অন্তর্নিহিত প্রকারের অন্তর্নিহিত প্রকারের জন্য, ই থেকে বাইটে রূপান্তরটি স্পষ্ট সংখ্যাসূচক রূপান্তর (§6.2.1) হিসাবে প্রান্ত থেকে বাইটে প্রক্রিয়াজাত হয় এবং বাইট থেকে ই তে রূপান্তর হিসাবে প্রক্রিয়া করা হয় একটি বদ্ধ থেকে সংখ্যায় রূপান্তর (§6.1.2)।

মূলত, রূপান্তর ক্রিয়াকলাপটি করার সময় এনামকে অন্তর্নিহিত ধরণের হিসাবে বিবেচনা করা হয়। ডিফল্টরূপে, একটি এনামের অন্তর্নিহিত ধরণ হয় Int32যার অর্থ রূপান্তরটি রূপান্তরটির মতো হ'ল বিবেচিত হয় Int32। এর অর্থ কোনও বৈধ intমান অনুমোদিত।

আমি সন্দেহ করি এটি মূলত পারফরম্যান্সের কারণে করা হয়েছিল। করা হলে enumএকটি সহজ অবিচ্ছেদ্য টাইপ এবং কোন অবিচ্ছেদ্য টাইপ রূপান্তর, যার ফলে CLR অতিরিক্ত চেক সব করতে প্রয়োজন নেই। এর অর্থ হল যে enumকোনও পূর্ণসংখ্যার ব্যবহারের সাথে তুলনা করার সময় একটি ব্যবহার করা আসলেই কোনও কার্যকারিতা হ্রাস পায় না, যা ফলস্বরূপ এর ব্যবহারকে উত্সাহিত করতে সহায়তা করে।


আপনি কি এই অদ্ভুত লাগছেন? আমি ভেবেছিলাম এনামের একটি মূল বিষয় হ'ল নিরাপদে বিভিন্ন সংখ্যার পূর্ণসংখ্যার গোষ্ঠী করা যা আমরা স্বতন্ত্র অর্থগুলিও দান করতে পারি। আমার কাছে কোনও এনাম টাইপ করে কোনও পূর্ণসংখ্যার মানটি হ'ল তার উদ্দেশ্যটি হারাতে পারে।
— jcvandan

@ ডর্মিশার: আমি সবেমাত্র সম্পাদনা করেছি এবং শেষে কিছুটা যুক্ত করেছি। আপনার পরে "সুরক্ষা" সরবরাহ করার জন্য একটি ব্যয় জড়িত রয়েছে। এটি সাধারণ ব্যবহারের সাথে বলা হচ্ছে , এটি আসলে কোনও সমস্যা নয়।
— রিড কোপসি

9

ডকুমেন্টেশন থেকে :

টাইপের দিনগুলির একটি পরিবর্তনশীল অন্তর্নিহিত ধরণের সীমার কোনও মান নির্ধারিত হতে পারে; মানগুলি নামমাত্র স্থিরদের মধ্যে সীমাবদ্ধ নয়।

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