列挙型の暗黙の変換をC#で定義できますか?


129

C#で列挙型の暗黙の変換を定義することは可能ですか?

これを達成できるものは?

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

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

そうでない場合、なぜそうではないのですか?


2
私もこれをしたいと思います。enum YesNo {Yes, No}暗黙的にブール値に変換できる列挙型があります。
大佐パニック

この概念はコンパイラのタイプセーフティチェックを無効にすることに注意してください。長期的には、末尾の「〜」のような明示的な変換の省略表現の方が良い場合があります。
crokusek 2016

リンクは無効になりました。リンクを削除するか、Webサイトのどこかに再投稿できますか?
ワイキ

回答:


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

これは、通常の列挙型を宣言するよりもかなり多くの作業です(ただし、上記のいくつかを共通のジェネリック基本クラスにリファクタリングできます)。基本クラスにIComparableとIEquatableを実装させ、DescriptionAttributesの値や宣言された名前などを返すメソッドを追加することで、さらに先に進むことができます。

私は基本クラス(RichEnum <>)を書いて、大げさな作業のほとんどを処理しました。

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);
    }
}

基本クラス(RichEnum)を以下に示します。

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;
        }
    }
}

投稿の少しのオフガードエラーを修正しました:-)これは、パブリックで静的な暗黙の演算子であるAccountStatus(byte value){return Convert(value);です。} Convert(byte)を返しません。
Mehdi LAMRANI、2011

このベースクラスをコンパイルしました。変更を編集してもよろしいですか?
sehe

64
この解決策は、演習として、または誰かのプログラミングスキルをテストするのに「正しい」かもしれませんが、実際にはこれを行わないでください。それはやり過ぎであるだけでなく、非生産的、保守不可能、そして地獄のように醜いです。そのためだけに列挙型を使用する必要はありません。明示的なキャストを置くか、const intを使用して静的クラスを記述します。
2014

3
基本的にJava enumを再実装していないのですか?
Agent_L 2016年

2
大きな問題の1つは、これらの静的な読み取り専用定数をswitchステートメントで使用できないことです。
Ian Goldby 2016

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();
    }
}

ただし、これはあまり効果的ではありません(明示的なキャストを行う場合と比較して)。

私が人々がこれを望んでいるのを見た主な時期の1つは、[Flags]ジェネリック、つまりbool IsFlagSet<T>(T value, T flag);メソッドを介して操作を行うためのものです。残念ながら、C#3.0はジェネリックの演算子をサポートしていませんが、このようなものを使用してこれを回避でき、ジェネリックで演算子を完全に利用できるようになります。


:ええ、それは私の最もC#4のために望んでいたのだったstackoverflow.com/questions/138367/...stackoverflow.com/questions/7244
キース・

@キース-うまくいきました、それから;-p動的/オペレーターサポートはCTPに組み込まれませんでしたが、オペレーターと動的の2つのアプローチを比較する準備ができたテストリグを用意しています(それがそこに着いたときvsジェネリックス/式)。
Marc Gravell

@キース-MiscUtilのOperatorクラスに旋回を与えたいかもしれません; 私はそれがあなたが望むもののほとんどをするだろうと確信しています。
Marc Gravell

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";

しかし、なぜ構造ですか?
Konrad、

1
本当に理由はありません。私が使用するstatic classと思います。最終的なILコードでは、どちらの場合も議論する利点はありません。
Glenn Slayden

18

Markの優れたRichEnumジェネリックベースクラスを採用しました。

修正

  1. 彼のライブラリから欠落しているビットが原因のコンパイルに関する多くの問題(特に:リソースに依存する表示名は完全には削除されていませんでしたが、現在は削除されています)
  2. 初期化は完璧ではありませんでした。最初に行ったのが基本クラスから静的な.Valuesプロパティにアクセスした場合、NPEが取得されます。CheckInitializedの間に、ベースクラスに不思議なように再帰的にCRTP)強​​制にTDerivedの静的構築を強制することで、これを修正しました。
  3. 最後に、CheckInitializedロジックを静的コンストラクターに移動しました(毎回のチェックのペナルティを回避するために、マルチスレッド初期化の競合状態。おそらくこれは私の箇条書き1.で解決できないことでした)。

素晴らしいアイデア+実装をマークしてくれた称賛、これが皆さん全員です。

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()を使用して説明属性を取得することはお勧めできません。属性がない場合、Single()は例外をスローしますが、SingleOrDefault()は例外をスローしません。
kerem 2012年

@kerem良い点、私はそれを更新しました(FirstOrDefault単一の属性しかないと想定しないために、を使用します)。そのようなことが「良いアイデア」であると仮定するかどうか(または、悪いことですが)は、もちろんコンテキストに依存します
sehe

1
これが好きですが、私は問題に遭遇しました:Windows 7 / .NET 4.5では、この行TDerived instance = (TDerived)field.GetValue(null);instanceになりnullます。Monoランタイムは、これを機能させる.NETのタイプ初期化とは異なるタイプの初期化の順序を持​​つ必要があるようです。不可解です!代わりに、そのコードを静的メソッドに移動して、サブクラスの型初期化子から呼び出す必要がありました。
agentnega 2014年

@agentnegaその追加をありがとう。それは誰かを助けるかもしれません。
sehe

@agentnega .net 4.5.1で同じ問題が発生しています。C#仕様に「違反」しているようです。最初に使用する前に値を初期化しないため、少なくともリフレクションを使用する場合はそうではありません。サブクラス( 'TDerived')を必要としない回避策を実装しました。@ sehe回答を編集して回避策を回答に追加するか、新しい回答を投稿する必要がありますか?
BatteryBackupUnit

5

enum型はメソッドを定義できないため、暗黙的な変換を宣言することはできません。C#の暗黙のキーワードは、 'op_'で始まるメソッドにコンパイルされ、この場合は機能しません。


4

おそらく可能ですが、列挙型は対象外です(メソッドを追加することはできません)。列挙型をそれに変換できるように、暗黙の変換を自分のクラスに追加できます。

public class MyClass {

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

MyClass m = MyEnum.One;

問題はなぜでしょうか?

一般に、.Netは、データが失われる可能性がある暗黙的な変換を回避します(また、そうする必要があります)。


3

列挙型のベースをlongとして定義すると、明示的な変換を実行できます。列挙型にはメソッドを定義できないため、暗黙の変換を使用できるかどうかはわかりません。

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

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

また、初期化されていない列挙は、デフォルトで0の値、つまり最初の項目になることに注意してください。そのため、上記の状況では、おそらく定義することも最善zero = 0です。


5
: longここは必要ありません。明示的な変換は、それがなくても正常に機能します。唯一の正当な暗黙の変換はゼロです。
Marc Gravell

3
番号; デフォルトの列挙型はInt32
Marc Gravellです。

1
参照:列挙型Foo {A、B、C} Console.WriteLine(Enum.GetUnderlyingType(typeof(Foo)));
Marc Gravell

14
なぜこれが回答としてマークされ、ポイントが多いのですか?これはOPの質問には関係ありません!!! 彼は暗黙の変換について話している...付加価値はnilです。
Mehdi LAMRANI

3
この質問は、明示的なキャストが理解されていることをすでに示唆しており、この質問は「明示的なキャストを回避するにはどうすればよいですか?」
キット10 2012

2

このため、列挙型は私にとってほとんど役に立ちません。OP。

私はいつもpic関連のことをやっています:

簡単な解決策

典型的な問題の例は、キー押下を検出するためのVirtualKeyセットです。

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]; 

ここでの問題は、列挙型を暗黙的にushortに変換できないため、列挙型で配列にインデックスを付けることができないことです(列挙型をushortに基づいていても)

この特定のコンテキストでは、列挙型は次のデータ構造によって廃止されます。。。。

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

1

MS .net(Mono以外)でコードを実行すると、seheの回答に関する問題を回避しました。私にとって、特に問題は.net 4.5.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();
}

注意

上記のコードには、Markの元の回答のすべての機能が組み込まれているわけではありません。

ありがとう

彼の実装を提供してくれたMarkRichEnum感謝し、いくつかの改善を提供してくれた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

このユーティリティを作成して、EnumPrimitiveEnumに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でコミットを参照してください

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、ゲーム自体が通常enumsで作成するsで識別される多くのものを備えたゲームフレームワークを持っていますが、フレームワークは何も知りません。(uint)フレームワークを呼び出すときにしなければならないのは苦痛でした。あなたの考えは逆に完璧に機能します。代わりにstruct格納しEnum、私が持ってstruct IdNumber格納するuintからではなく、暗黙的に変換Enumゲーム用途だが。フレームワークのparamsをと入力する代わりに、と入力するuintことができますIdNumber。フレームワークは内部でそれらを効率的に渡すことができます。
ケビン

-2

列挙型の暗黙的な変換を導入すると、型の安全性が損なわれるため、そうすることはお勧めしません。なぜそれをしたいのですか?私が見たこの唯一のユースケースは、事前定義されたレイアウトで構造体に列挙値を入れたい場合です。しかし、それでも、構造体で列挙型を使用して、マーシャラーにこれをどうするかを伝えることができます。


列挙型の暗黙的な変換を使用します。SPMetalを使用して、同じサイトコレクションの複数のサイトでLINQ to SharePointクラスを生成する。一部のリストは1つのサブサイトにあり、他のリストは別のサブサイトにあります。SPMetalがコードを生成する方法により、コレクションの複数のリストで使用されるサイト列は、複数の名前空間で定義される場合があります。ただし、ある名前空間の選択フィールド列挙型を別の名前空間の同じ列挙型に変換する必要があります。暗黙的な変換は非常に役立ちます。
ザレフェス2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.