Реализация типов Nullable в существующих объектах - PullRequest
5 голосов
/ 07 января 2010

Я модернизирую существующее приложение, в котором реализован класс Constants для домашнего пивоварения в объектах business и datalayer.

Я хочу заменить это типами Nullable и исключить класс констант, который выглядит следующим образом, но со всеми типами данных, не допускающими NULL:

class Constants
{
    public static int nullInt
    {
        get { return int.MinValue; }
    }
}

Эти константы vaules используются как значения по умолчанию для почти всех свойств объекта, например:

private decimal _unitPrice = Constants.nullInt;
public decimal UnitPrice
{
    get { return _unitPrice; }
    set { _unitPrice = (value == null) ? Constants.nullInt : value; }
}

Это вызывает некоторую путаницу при сохранении свойств объекта в БД, поскольку все десятичные и целые должны быть проверены на наличие псевдо-нулевых значений, иначе вы сохраните такие вещи, как int.MinValue, в БД.

    private void Save()
    {
        //Datalayer calls and other props omitted
        SqlParameter sqlParm = new SqlParameter();
        sqlParm.Value = (this.UnitPrice == Constants.nullInt) ? DBNull.Value : (object)this.UnitPrice;

    }

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

    public decimal? UnitPrice { get; set; }

    private void Save()
    {
        //Datalayer calls and other props omitted
        SqlParameter sqlParm = new SqlParameter();
        sqlParm.Value = this.UnitPrice ?? DBNull.Value;
    }

РЕДАКТИРОВАТЬ: Спасибо за двойную проверку моего рефакторинга, и да, нулевая проверка на SET свойства в исходном коде будет избыточной. Я все еще хочу знать, может ли код, реализующий этот объект, иметь какие-либо проблемы, связанные с изменением типа на десятичное? с десятичное

Ответы [ 2 ]

5 голосов
/ 07 января 2010
public decimal? UnitPrice { get; set; }

private void Save()
{
    //Datalayer calls and other props omitted
    SqlParameter sqlParm = new SqlParameter();
    sqlParm.Value = this.UnitPrice ?? DBNull.Value;
}

Я нахожу это абсолютно нормально. Вот как это должно работать.

0 голосов
/ 07 января 2010

Мне немного неясно, как реализовать описанный выше метод набора свойств, так как десятичное число никогда не может быть нулевым, поэтому я думаю, что этот тест избыточен. Я включил пример кода, который можно вставить в консольное приложение, которое должно помочь вам.

Вы будете испытывать очень мало рефакторинга своего кода из-за перехода на типы данных, допускающие значение NULL. Это будет хорошим шагом с вашей стороны в очистке вашего кода и избежании потенциальных ошибок вашей текущей реализации.

Если ничего другого, выигрыш в производительности, скорее всего, окупит ваши усилия. Так сказать, ничто не будет полностью самонастраиваемым, но если вы посмотрите на приведенный ниже код, то увидите, что в предоставленных вами сценариях очень мало влияния.

Пример

using System;
using System.Data.SqlClient;

namespace NullableTypes
{
    class Program
    {
        static class Constants
        {
            public static decimal NullDecimal
            {
                get { return decimal.MinValue; }
            }
        }

        public class ProductTheOldWay
        {
            public string Name { get; set; }
            public decimal UnitPrice { get; set; }

            public ProductTheOldWay()
            {
                Name = string.Empty;
                UnitPrice = Constants.NullDecimal;
            }

            public override string ToString()
            {
                return "Product: " + Name + " Price: " + 
                       ((UnitPrice == Constants.NullDecimal) 
                         ? "Out of stock" 
                         : UnitPrice.ToString());
            }

            public void Save()
            {
                //Datalayer calls and other props omitted
                var sqlParm = new SqlParameter
                {
                    Value = (UnitPrice == Constants.NullDecimal) 
                             ? DBNull.Value 
                             : (object)UnitPrice
                };

                //save to the database...
                Console.WriteLine("Value written to the database: " + sqlParm.Value);
            }
        }

        public class ProductTheNewWay
        {
            public string Name { get; set; }
            public decimal? UnitPrice { get; set; }

            public ProductTheNewWay()
            {
                Name = string.Empty;
            }

            public override string ToString()
            {
                return "Product: " + Name + " Price: " + 
                       ((UnitPrice.HasValue) 
                         ? UnitPrice.ToString() 
                         : "Out of stock");
            }

            public void Save()
            {
                //Datalayer calls and other props omitted
                var sqlParm = new SqlParameter
                {
                    Value = UnitPrice
                };

                //save to the database...
                Console.WriteLine("Value written to the database: " + sqlParm.Value);
            }
        }

        static void Main()
        {
            var oldProduct1 = new ProductTheOldWay
            {
                Name = "Widget",
                UnitPrice = 5.99M
            };

            var oldProduct2 = new ProductTheOldWay
            {
                Name = "Rare Widget",
                UnitPrice = Constants.NullDecimal // out of stock
            };

            Console.WriteLine(oldProduct1);
            Console.WriteLine(oldProduct2);

            Console.WriteLine("Saving...");
            oldProduct1.Save();
            oldProduct2.Save();

            Console.ReadLine();

            var newProduct1 = new ProductTheNewWay
            {
                Name = "Widget",
                UnitPrice = 5.99M
            };

            var newProduct2 = new ProductTheNewWay
            {
                Name = "Rare Widget"
                /* UnitPrice = null by default */
            };

            Console.WriteLine(newProduct1);
            Console.WriteLine(newProduct2);

            Console.WriteLine("Saving...");
            newProduct1.Save();
            newProduct2.Save();

            Console.ReadLine();

            // as a further example of the new property usage..

            if (newProduct1.UnitPrice > 5)
                Console.WriteLine(newProduct1);

            Console.WriteLine("Using nullable types is a great way to simplify code...");

            Console.ReadLine();    
        }
    }
}

выход

Product: Widget Price: 5.99  
Product: Rare Widget Price: Out of stock  
Saving...  
Value written to the database: 5.99  
Value written to the database:  

Product: Widget Price: 5.99  
Product: Rare Widget Price: Out of stock  
Saving...  
Value written to the database: 5.99  
Value written to the database:  

Product: Widget Price: 5.99  

Использование обнуляемых типов данных - отличный способ упростить код ...

Дайте мне знать, если есть более конкретные детали реализации, которые касаются вашего переключения.

...