views:

224

answers:

2

I am upgrading an existing application that has implemented a home-brew Constants class in its business and datalayer objects.

I want to replace this with Nullable types and do-away with the constants class, that looks like this, but with all non-nullable data types:

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

These constants vaules are used as defaults on almost all the object properties like this:

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

This causes some confusion on saving object properties to the Db as all decimal's and ints have to be checked for psudo null values or else you save things like int.MinValue to the Db.

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

    }

Ok so now the question.. I want to change things around using Nullable value types as in my example below, will the change in a property from a decimal to a decimal? affect any code thats implementing these objects?

    public decimal? UnitPrice { get; set; }

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

EDIT: Thanks for the double check of my refactor, and yes the null check on the SET of the property in the original code would be redundant. I still want to know if code that implements this object could have any issues from the change of type to decimal? from decimal

A: 

I'm a little unclear as to the implementation of your above property set method as a decimal can never be null so this test is redundant I think. I'm including some sample code that can be dropped into a Console application that should clear things up for you. You will experience very little refactoring of your code due to switching over to the nullable data types. This will be a good move on your part in cleaning up your code and avoiding the potential pitfalls of your current implementation. If nothing else, the performance gains you'll receive would likely make the effort worth your while. Nothing will be completely plug-n-play so to speak but if you look at the below code you'll see there's very little impact in the scenarios you've provided.

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 data types is a great way to simplify code...");

            Console.ReadLine();

        }
    }
}

Output...


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 Using nullable data types is a great way to simplify code...

Let me know if there are more specific implementation details that concern you making the switch.

Dave Jellison
The other benefit is the code is cleaner and more readable obviously. I'm sure this is part of the reason you want to make the switch in addition to performance and dependability issues as well.
Dave Jellison
+4  A: 
public decimal? UnitPrice { get; set; }

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

I find this absolutely ok. This is how it is supposed to work.

this. __curious_geek