Thursday, December 18, 2008
Comparing Default Values In Generic Classes
Ever since they were introduced in C# 2.0, most programmers have loved generics. I know I do! But, it can be a bit tricky to determine if a variable has been assigned or is still the default value if you do not know how to do it.
Consider the following class, and note that it
The code
So, the question becomes just how do you do such a comparison if you cannot do that? If you know
But, that will only work for reference types and we have not put any such constraints on
Actually, as a side note, that code will compile for both reference types and value types but will always return false for value types. This is because, believe it or not, starting with C# 2.0, you can compare any value type to null using the
So, if you cannot compare against
With that change to the
Consider the following class, and note that it
- Is a generic class
- Has a field name
_field
- Initialize
_fieldto the default value in the constructor
- Has a property
IsDefaultValuethat should return true if_fieldis still the default value (or has been assigned back the default value).
public class MyClass
{
private T _field;
public MyClass()
{
_field = default(T);
}
public T Field
{
get
{
return _field;
}
set
{
_field = value;
}
}
public bool IsDefaultValue
{
get
{
// The following line does not compile!
return ( _field == default(T) );
}
}
}
The code
default(T) causes the compiler to use the default that is appropriate for the type (null for refrence types, 0 for an int, 0.0 for a double, etc.). This is used in the constructor to assign the default value to _field. Therefore, it seems logical that we can do a comparison such as ( _field == default(T) ). But, the compiler does not like it and will complain with a message like Operator '==' cannot be applied to operands of type 'T' and 'T'.So, the question becomes just how do you do such a comparison if you cannot do that? If you know
T is a reference type, you can compare against null.
// Works only if T is a reference time
return ( _field == null );
But, that will only work for reference types and we have not put any such constraints on
T.Actually, as a side note, that code will compile for both reference types and value types but will always return false for value types. This is because, believe it or not, starting with C# 2.0, you can compare any value type to null using the
== operator, but the comparison will always return false. This is a side effect of adding support for nullable types via ?.
int x = 1;
if (x == null)... // Always returns false
int? y = null;
if (y == null)... // Returns true since y is null
y = 1;
if (y == null)... // Return false since y is not null
if (x == y) ... // Return true since x and y have the same value of 1
So, if you cannot compare against
default(T) or null, what can you do to see if _field is currently set to the default value? The best way I have found to do this is shown below.
public bool IsDefaultValue
{
get
{
return object.Equals(_field, default(T) );
}
}
With that change to the
IsDefaultValue method, it compiles and works as you would expect.
MyClass<int> obj1 = new MyClass<int>();
bool flag1a = obj1.IsDefaultValue; // true
obj1.Field = 1;
bool flag1b = obj1.IsDefaultValue; // false
MyClass<object> obj2 = new MyClass<object>();
bool flag2a = obj2.IsDefaultValue; // true
obj2.Field = new object();
bool flag2b = obj1.IsDefaultValue; // false
Subscribe to Posts [Atom]