Мы можем определить неявные преобразования перечислений в c#?

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

125
задан Nick Edwards 17 August 2016 в 05:17
поделиться

6 ответов

Есть решение. Рассмотрим следующее:

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;
        }
    }
}
125
ответ дан 24 November 2019 в 01:01
поделиться

При определении основы перечисления как длинное затем, можно выполнить явное преобразование. Я не знаю, можно ли использовать неявные преобразования, поскольку перечислениям нельзя было определить методы на них.

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

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

кроме того, знать с этим то, что uninitalised перечисление примет значение по умолчанию к этим 0 значениям или первому объекту - так в ситуации выше его, вероятно, было бы лучшим для определения zero = 0 также.

3
ответ дан 24 November 2019 в 01:01
поделиться

Вы не можете сделать implict преобразований (за исключением нуля), и Вы не можете записать свои собственные методы экземпляра - однако, можно, вероятно, записать собственные дополнительные методы:

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); метод. К сожалению, C# 3.0 не поддерживает операторы на дженериках, но можно обойти это использование вещи как это , которые делают операторы полностью доступными с дженериками.

31
ответ дан 24 November 2019 в 01:01
поделиться

Вы, вероятно, могли, но не для перечисления (Вы не можете добавить метод к нему). Вы могли добавить неявное преобразование в Вас собственный класс, чтобы позволить перечислению быть преобразованным в него,

public class MyClass {

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

MyClass m = MyEnum.One;

, вопрос будет состоять в том почему?

В общем .NET избегает (и Вы должны также), любое неявное преобразование, где данные могут быть потеряны.

4
ответ дан 24 November 2019 в 01:01
поделиться

Вы не можете объявить неявные преобразования на перечислимых типах, потому что они не могут определить методы. C# , неявный , ключевое слово компилирует в метод, запускающийся с 'op _', и это не работало бы в этом случае.

3
ответ дан 24 November 2019 в 01:01
поделиться

Представление неявных преобразований для перечислимых типов повредило бы безопасность типа, таким образом, я не рекомендую сделать это. Почему Вы хотели бы сделать это? Единственный вариант использования для этого, которое я видел, - когда Вы хотите поместить перечислимые значения в структуру с предопределенным расположением. Но даже затем, можно использовать перечислимый тип в структуре и просто сказать Marshaller, что он должен сделать с этим.

-1
ответ дан 24 November 2019 в 01:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: