Как создать класс, использующий универсальный тип, допускающий типы, допускающие значение NULL, и типы, не допускающие значения NULL

Я пытаюсь создать класс для использования в качестве поля в других объектах, которые могут содержать временное несохраненное значение до тех пор, пока для объекта не будет вызван метод SaveChanges, чтобы я мог передать значение в сохраненную процедуру, которая обновит любые несохраненные значения. -null поля с новым значением и оставить поля с нулевым значением в качестве исходных значений.

Я хочу уметь это делать:

private Field<int> MyInt;
private Field<int?> MyNullableInt;
private Field<string> MyString;

а затем сможете использовать объекты поля следующим образом:

MyInt = new Field<int>(1);    // initialise with a value
MyInt.Value = 2;              // assign a new value internally marking it as having a new value
int x = MyInt.Value;          // read the current value
int? newInt = MyInt.NewValue; // read the newly set value, or null if there is no new value

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

  • типы значений, такие как int, bool и т. д., которые имеют ограничение NOT NULL в базе данных.
  • типы значений, такие как int ?, bool? и т. д., которые допускают NULL в базе данных.
  • ссылочные типы, такие как строка, которые всегда допускают значение NULL.

Я все еще изучаю Generics, но я начинаю их понимать, однако я немного зациклился на этом, потому что я могу создать объект Field по мере необходимости выше, который работает с типом, не допускающим значения NULL, или типом, допускающим значение NULL. , но не то и другое одновременно.

Вот что я до сих пор придумал:

protected class Field<T> where T : struct {
    private T _Field;
    private bool _IsNew;

    public Field(T InitialValue) {
        _Field = InitialValue;
        _IsNew = false;
    }

    public T Value {
        get { return _Field; }
        set { 
            if (!_Field.Equals(value)) { 
                _Field = value; 
                _IsNew = true; 
            } 
        }
    }

    public Nullable<T> NewValue {
        get {
            if (_IsNew) {
                _IsNew = false;
                return _Field;
            }
            return null; 
        }
    }

    public bool IsNew { get { return _IsNew; } }

}

Это хорошо работает. Я также могу изменить ограничение типа на where T : class и изменить Nullable<T> на T в методе NewValue, что заставляет его работать с типами, допускающими значение NULL, но как мне заставить его работать со всеми типами данных? Мне действительно нужно создавать два разных класса для обработки двух разных сценариев?

Спасибо Бен


person BG100    schedule 11.10.2010    source источник
comment
Это дополнительное примечание, но, пожалуйста, используйте строчные буквы в полях и переменных.   -  person Steven Sudit    schedule 11.10.2010


Ответы (1)


что мешает делать то, что хочешь? Я предполагаю, что это ограничение где. Если вы его уроните, я не понимаю, в чем проблема.

ИЗМЕНИТЬ

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

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

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

person mfeingold    schedule 11.10.2010
comment
Если я откажусь от ограничения where, это не позволит мне вернуть значение NULL для NewValue. - person BG100; 11.10.2010
comment
попробуйте default (T) вместо return null - person asawyer; 11.10.2010
comment
тогда вы должны исключить частное поле ‹int› MyInt из списка вещей, которые вы хотите здесь осветить - person mfeingold; 11.10.2010
comment
Правильно, ограничение не только профилактическое. Как только вы убедитесь, что тип наследует или реализует что-то, ваш код может полагаться на это. - person Steven Sudit; 11.10.2010
comment
@mfeingold: Я не могу, потому что тогда кто-то может просто дать мне ответ, чтобы изменить его для работы с типами, допускающими значение NULL, но не с типами, не допускающими значения NULL, но я хочу что-то, что охватывает оба. - person BG100; 11.10.2010
comment
@ BG100, в дополнение к тому, что указал asawyer, new T() вернет 'null' для типа, допускающего значение NULL (на самом деле это не NULL, но он помещается в NULL и сравнивается как true с NULL). Для структуры вы гарантированно получите конструктор без параметров (который создает «пустую» структуру). Обнуляемая структура - это структура, только со специальной поддержкой со стороны CLR и C #, чтобы она выглядела так, как будто она может иметь значение null. - person Dan Bryant; 11.10.2010
comment
@ BG100: Я объясню. Если вы говорите, что T должен реализовывать IDisposable, вы можете вызвать Dispose для его экземпляра. Если бы вы не поставили это ограничение, компилятор не будет иметь никаких гарантий, что вызов законен, поэтому он не будет разрешен. Это помогает? - person Steven Sudit; 11.10.2010
comment
@asawyer: хорошо, я смотрел на это, но тогда, если T - это int, мне все равно нужно NewValue, чтобы вернуть int? тип со значением null. Я начинаю думать, что то, чего я хочу, невозможно! - person BG100; 11.10.2010
comment
Вы не можете получить и то, и другое. Либо ваш общий класс знает что-то о нулевых значениях, присваиваемых значению, и тогда у вас не может быть типа значения (например, int) в качестве разрешенного типа, либо у вас нет. И если ваш класс не имеет ограничения, вы все равно можете присвоить значение null значению, ЕСЛИ значение имеет ссылочный тип - person mfeingold; 11.10.2010
comment
@mfeingold: Хорошо, я думаю, мне нужно создать два класса, чтобы охватить оба сценария. Можете ли вы вставить этот комментарий в свой ответ? Тогда я приму это! - person BG100; 11.10.2010