Синтаксис typedef с указателями на функции-члены

Переменная c # бесполезна.

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

  • Предоставить неявный оператор для преобразования из вашего типа в общий int, поэтому вам не нужно делать бросок.
  • Предоставить явный оператор для преобразования из int в ваш тип , который выдает ошибку, если целое число не удовлетворяет ограничению, например (int x) => (x> = 0 & amp; & amp; x & lt; = 2).

Если используя этот метод, создайте универсальный неизменный базовый класс, такой как ConstrainedNumber<T>, который имеет конструктор, который принимает значение T и делегирует для ограничения: delegate bool NumberConstraint<T>(T value). Конструктор должен запускать значение через делегат ограничения и вызывать исключение, если ему не удается выполнить ограничение. Базовый класс должен также заботиться о операции неявного преобразования в T и должен обрабатывать равенство, перегружая объект. Элементы (object) и object.GetHashCode (), определяющие операторы == и! = Для типа ConstrainedNumber<T> и реализующие IEquatable<T> и IEquatable<ConstrainedNumber<T>>. Я также рекомендую определить конструктор копирования для базового класса и всех производных типов. Клонирование затем может быть реализовано чисто в базовом классе путем извлечения конструктора копирования посредством отражения, но это совершенно необязательно. Вы можете понять реализацию ConstrainedNumber<T> самостоятельно, если я уже не разместил ее где-то в stackoverflow.

Вы можете указать значения static readonly в своем производном ConstrainedNumber, чтобы вы могли обращаться к ним так же, как enum.

public sealed class ReturnValue: ConstrainedNumber<int>
{
    public static readonly NumberConstraint<int> constraint = (int x) => (x >= 0 && x < 3);

    public static readonly ReturnValue Success = new ReturnValue(0);
    public static readonly ReturnValue FailReason1 = new ReturnValue(1);
    public static readonly ReturnValue FailReason2 = new ReturnValue(2);

    private ReturnValue( int value ): base( value, constraint ) {}
    private ReturnValue( ReturnValue original ): base (original) {} //may be used to support IClonable implementation in base class
    public static explicit operator ReturnValue( int value )
    {
        switch(value) //switching to return an existing instance is more efficient than creating a new one and re-checking the constraint when there is a limited number of allowed values; if the constraint was more generic, such as an even number, then you would instead return a new instance here, and make your constructors public.
        {
            case 0: return Success;
            case 1: return FailReason1;
            case 2: return FailReason2;
        }
        throw new ArgumentException( "Value fails to meet the constraint defined for " + typeof(ReturnValue).FullName + ".", "value" );
    }

}

Вы можете использовать эту технику для любого ограничения. Например, класс с названием EvenNumber может иметь ограничение, которое возвращает true, если заданное число четное. В этом случае вы просто сделаете свои конструкторы общедоступными и упростите свой оператор статического преобразования, чтобы просто вернуть новый EvenNumber, вместо того чтобы переключиться на возврат одного из ограниченных существующих экземпляров.

Его можно использовать как это:

EvenNumber x = (EvenNumber)2;
EvenNumber y = (EvenNumber)3; //throws exception "Value fails to meet the constraint defined for {namespace}.EvenNumber."  A c# enum would stupidly allow such a cast, creating an invalid EvenNumber, breaking the object-oriented model
int z = x; //implicit conversion, no cast necessary;
23
задан muxmux 7 June 2011 в 14:17
поделиться