Googling is only coming up with the keyword, but I stumbled across some code that says
MyVariable = default(MyObject);
and I am wondering what it means.
For a reference-type, it returns null
For a value-type other than Nullable<T> it returns a zero-initialized value
For Nullable<T> it returns the empty (pseudo-null) value (actually, this is a re-statement of the second bullet, but it is worth making it explicit)
The biggest use of default(T) is in generics, and things like the Try... pattern:
bool TryGetValue(out T value) {
if(NoDataIsAvailable) {
value = default(T); // because I have to set it to *something*
return false;
}
value = GetData();
return true;
}
As it happens, I also use it in some code-generation, where it is a pain to initialize fields / variables - but if you know the type:
bool someField = default(bool);
int someOtherField = default(int);
global::My.Namespace.SomeType another = default(global::My.Namespace.SomeType);
default keyword will return null for reference types and zero for numeric value types.
For structs, it will return each member of the struct initialized to zero or null depending on whether they are value or reference types.
from MSDN
Simple Sample code :<br>
class Foo
{
public string Bar { get; set; }
}
struct Bar
{
public int FooBar { get; set; }
public Foo BarFoo { get; set; }
}
public class AddPrinterConnection
{
public static void Main()
{
int n = default(int);
Foo f = default(Foo);
Bar b = default(Bar);
Console.WriteLine(n);
if (f == null) Console.WriteLine("f is null");
Console.WriteLine("b.FooBar = {0}",b.FooBar);
if (b.BarFoo == null) Console.WriteLine("b.BarFoo is null");
}
}
OUTPUT:
0
f is null
b.FooBar = 0
b.BarFoo is null
Specifies the default value of the
type parameter.This will be null for
reference types and zero for value
types.
See default
Default value of MyObject. See default Keyword in Generic Code (C# Programming Guide) (MSDN):
In generic classes and methods, one issue that arises is how to assign
a default value to a parameterized type T when you do not know the
following in advance:
Whether T will be a reference type or a value type.
If T is a value type, whether it will be a numeric value or a struct.
Given a variable t of a parameterized type T, the statement t = null
is only valid if T is a reference type and t = 0 will only work for
numeric value types but not for structs. The solution is to use the
default keyword, which will return null for reference types and zero
for numeric value types. For structs, it will return each member of
the struct initialized to zero or null depending on whether they are
value or reference types. The following example from the
GenericList class shows how to use the default keyword. For more
information, see Generics Overview.
public class GenericList<T>
{
private class Node
{
//...
public Node Next;
public T Data;
}
private Node head;
//...
public T GetNext()
{
T temp = default(T);
Node current = head;
if (current != null)
{
temp = current.Data;
current = current.Next;
}
return temp;
}
}
The default keyword returns the "default" or "empty" value for a variable of the requested type.
For all reference types (defined with class, delegate, etc), this is null. For value types (defined with struct, enum, etc) it's an all-zeroes value (for example, int 0, DateTime 0001-01-01 00:00:00, etc).
It's mostly used with generic code that can be applied to both reference and value types, because you can't assign null to a value type variable.
It will set the default value of an object to a variable:
null for reference types and 0 for value types.
Perhaps this may help you:
using System;
using System.Collections.Generic;
namespace Wrox.ProCSharp.Generics
{
public class DocumentManager < T >
{
private readonly Queue < T > documentQueue = new Queue < T > ();
public void AddDocument(T doc)
{
lock (this)
{
documentQueue.Enqueue(doc);
}
}
public bool IsDocumentAvailable
{
get { return documentQueue.Count > 0; }
}
}
}
It is not possible to assign null to generic types. The reason is that a generic type can also be instantiated as a value type, and null is allowed only with reference types. To circumvent this problem, you can use the default keyword. With the default keyword, null is assigned to reference types and 0 is assigned to value types.
public T GetDocument()
{
T doc = default(T);
lock (this)
{
doc = documentQueue.Dequeue();
}
return doc;
}
The default keyword has multiple meanings depending on the context where it is used. The switch
statement uses a default for defining the default case, and with generics the default is used to initialize generic types either to null or 0 depending on if it is a reference or value type.
When constraints have not been applied to restrict a generic type parameter to be a reference type, then a value type, such as a struct, could also be passed. In such cases, comparing the type parameter to null would always be false, because a struct can be empty, but never null
wrong code
public void TestChanges<T>(T inputValue)
try
{
if (inputValue==null)
return;
//operation on inputValue
}
catch
{
// ignore this.
}
}
corrected
public void TestChanges<T>(T inputValue)
try
{
if (object.Equals(inputValue, default(T)) )
return;
//operation on inputValue
}
catch
{
// ignore this.
}
}
Another good use of default(T) is when compiler can't determine returning type, like in here
class X
{
public int? P {get; set;}
}
// assigning in code
var x = new X();
// consider coll["key"] returns object boxed value
// data readers is one such case
x.P = myReader["someColumn"] == DbNull.Value ? default(int?) : (int)myReader["someColumn"];
Related
In this contrived C# 8 example:
#nullable enable
class Fred<T>
{
T Value; // If T is a nullable type, Value can be null.
public Fred() { }
public void SetValue(T value) { Value = value; }
public T GetValue() { return Value; }
public string Describe() { return Value.ToString() ?? "oops"; }
}
class George
{
George()
{
Fred<George> fredGeorge = new Fred<George>();
George g = fredGeorge.GetValue();
Fred<float> fredFloat = new Fred<float>();
float f = fredFloat.GetValue();
}
}
I have three design goals:
The compiler should warn me if I write any methods for Fred that blindly assume that 'Value' will never be null
The compiler should warn me if I write any methods outside of Fred (say, in George) that blindly assume that 'GetValue' will never return null.
No compiler warnings (if I have written code that doesn't blindly assume values won't be null)
So this first version isn't bad, I get a warning in Fred that Describe() might be dereferencing a null reference (satisfies goal #1) but I also get a warning that Value is uninitialized in Fred's constructor (violates goal #3) and George compiles without any warnings (violates goal #2). If I make this change:
public Fred() { Value = default; }
George still compiles without warnings (violates goal #2) and I get a different warning in Fred's constructor about a "Possible null reference assignment" (violates goal #3).
I can get rid of the possible null reference assignment by using the null-forgiving operator:
public Fred() { Value = default!; }
And now Fred only has the correct warning (possible dereference in Describe()), but George also compiles without warning (violates goal #2).
If I try to indicate that 'Value' can be null:
T? Value;
I get a compiler error that "A nullable type parameter must be known to be a value type or non-nullable reference type" so that's no good.
If I go back to
T Value;
and add the "MaybeNull" attribute:
[return: MaybeNull]
public T GetValue() { return Value; }
I get two warnings - one in Fred.Describe() warning of a possible null dereference (correct) and one in George warning that fredGeorge.GetValue() might be null (correct). There is no warning about fredFloat.GetValue() being null (correct).
So after adding code to expect null references, what I end up with is this:
class Fred<T>
{
T Value;
public Fred()
{
Value = default!;
}
public void SetValue(T value)
{
Value = value;
}
[return: MaybeNull]
public T GetValue()
{
return Value;
}
public string Describe()
{
return (Value == null) ? "null" : (Value.ToString() ?? "ToString is null");
}
}
class George
{
George()
{
Fred<George> fredGeorge = new Fred<George>();
George? g = fredGeorge.GetValue();
Fred<float> fredFloat = new Fred<float>();
float f = fredFloat.GetValue();
}
}
Is this the correct pattern for this functionality?
In System.Diagnostics.CodeAnalysis there is an attribute AllowNullAttribute that specifies that null is allowed as an input even if the corresponding type disallows it. I would use this attribute in your final sample to:
Decorate field Value. This will allow us to remove null-forgiving operator in the assignment Value = default. Compiler will not warn us about Possible null reference assignment, because now it knows that null value can be assigned to the property Value.
Decorate argument T value of the method SetValue. It will allow to pass null value to the method SetValue without getting compiler warning Cannot convert null literal to non-nullable reference type. (Currently if we pass null value to the method SetValue we will get this warning)
Here is final sample with suggested changes:
class Fred<T>
{
// AllowNull attribute says that a null value
// can be assigned to the field Value.
[AllowNull]
private T Value;
public Fred()
{
// Now we can delete null-forgiving operator, because compiler knows
// that null value can be assigned to the field Value.
Value = default;
}
// AllowNull attribute says that a null value
// can be passed to the method SetValue.
public void SetValue([AllowNull] T value)
{
Value = value;
}
[return: MaybeNull]
public T GetValue()
{
return Value;
}
public string Describe()
{
return (Value == null) ? "null" : (Value.ToString() ?? "ToString is null");
}
}
class George
{
George()
{
Fred<George> fredGeorge = new Fred<George>();
George? g = fredGeorge.GetValue();
// Compiler does not warn us "Cannot convert null literal to
// non-nullable reference type" because it knows that a null
// value can be passed to the method SetValue.
fredGeorge.SetValue(null);
Fred<float> fredFloat = new Fred<float>();
float f = fredFloat.GetValue();
}
}
If we use a regular property instead of the field Value with a pair of methods GetValue and SetValue then we can rewrite final sample in a clearer way:
class Fred<T>
{
// Here we tell that:
// 1) a null value can be assigned;
// 2) a null value can be returned.
[AllowNull, MaybeNull]
public T Value { get; set; }
public Fred()
{
// Compiler does not warn us "Possible null reference assignment".
// It knows that a null value can be assigned. It is correct.
// We can delete null-forgiving operator.
Value = default;
}
public string Describe()
{
// If we delete null checking, then we get a warning "Dereference of
// a possibly null reference". It is correct. Compiler helps us to avoid
// NullReferenceException.
return (Value == null) ? "null" : (Value.ToString() ?? "ToString is null");
}
}
class George
{
George()
{
Fred<George> fredGeorge = new Fred<George>();
// Compiler warns us "Converting null literal or possible null
// value to non-nullable type". It is correct.
// We should use nullable reference type George?.
George g = fredGeorge.Value;
// Compiler does not warn us "Cannot convert null literal to
// non-nullable reference type". It knows that a null value
// can be passed to the method SetValue. It is correct.
fredGeorge.Value = null;
Fred<float> fredFloat = new Fred<float>();
float f = fredFloat.Value;
}
}
I want to do some comparing of member properties at runtime but value type prohibits unusual behaviour.
I have something like the following
public static object DefaultValue(this Type type)
{
return type.IsValueType ? Activator.CreateInstance(type) : null;
}
class ExampleClass
{
public string Id { get; set; }
public string Title { get; set; }
public decimal Price { get; set; }
public XElement ToXml()
{
var srcTree = from prop in GetType().GetProperties()
let value = prop.GetValue(foo, null)
where value != prop.PropertyType.DefaultValue()
select new XElement(prop.Name.ToLower(), value);
...
}
}
if I initialize my object new ExampleClass() I find the price with a value of 0. I can confirm DefaultValue() returns 0 for the price which is not equal to 0 during equality comparison. Is because now it’s comparing objects or what. What can I achieve the behaviour I want?
object DefaultValue(this Type type)
the method returns an object, Although you judge whether it is a value type in the method and use Activator.CreateInstance create the type dynamically.
but the value will be boxing in an object be an object type value instead of your expected value type.
When you used == on an expression of type object, it'll use ReferenceEquals to compare the references instead of value.
var srcTree = from prop in GetType().GetProperties()
let value = prop.GetValue(foo, null)
where !Equals(value, prop.PropertyType.DefaultValue())
select new XElement(prop.Name.ToLower(), value);
c# online
Here is a sample for your case
we can saw defaultVal object set a value 0, which is int type (doing boxing).
dymanicVal created int by Activator.CreateInstance method.
Then when we use == to compare two objects they will compare their reference instead of int value
so you can try to use Equals method to compare the value will call RuntimeHelpers.Equals method then compare their value instead of references.
object defaultVal = 0;
object dymanicVal = Activator.CreateInstance(typeof(int));
Console.WriteLine(Equals(defaultVal, dymanicVal)); //True
Console.WriteLine(defaultVal == dymanicVal); //false
c# online
I have a generic method defined like this:
public void MyMethod<T>(T myArgument)
The first thing I want to do is check if the value of myArgument is the default value for that type, something like this:
if (myArgument == default(T))
But this doesn't compile because I haven't guaranteed that T will implement the == operator. So I switched the code to this:
if (myArgument.Equals(default(T)))
Now this compiles, but will fail if myArgument is null, which is part of what I'm testing for. I can add an explicit null check like this:
if (myArgument == null || myArgument.Equals(default(T)))
Now this feels redundant to me. ReSharper is even suggesting that I change the myArgument == null part into myArgument == default(T) which is where I started. Is there a better way to solve this problem?
I need to support both references types and value types.
To avoid boxing, the best way to compare generics for equality is with EqualityComparer<T>.Default. This respects IEquatable<T> (without boxing) as well as object.Equals, and handles all the Nullable<T> "lifted" nuances. Hence:
if(EqualityComparer<T>.Default.Equals(obj, default(T))) {
return obj;
}
This will match:
null for classes
null (empty) for Nullable<T>
zero/false/etc for other structs
How about this:
if (object.Equals(myArgument, default(T)))
{
//...
}
Using the static object.Equals() method avoids the need for you to do the null check yourself. Explicitly qualifying the call with object. probably isn't necessary depending on your context, but I normally prefix static calls with the type name just to make the code more soluble.
I was able to locate a Microsoft Connect article that discusses this issue in some detail:
Unfortunately, this behavior is by design and there is not an easy solution to enable use of with type parameters that may contain value types.
If the types are known to be reference types, the default overload of defined on object tests variables for reference equality, although a type may specify its own custom overload. The compiler determines which overload to use based on the static type of the variable (the determination is not polymorphic). Therefore, if you change your example to constrain the generic type parameter T to a non-sealed reference type (such as Exception), the compiler can determine the specific overload to use and the following code would compile:
public class Test<T> where T : Exception
If the types are known to be value types, performs specific value equality tests based on the exact types used. There is no good "default" comparison here since reference comparisons are not meaningful on value types and the compiler cannot know which specific value comparison to emit. The compiler could emit a call to ValueType.Equals(Object) but this method uses reflection and is quite inefficient compared to the specific value comparisons. Therefore, even if you were to specify a value-type constraint on T, there is nothing reasonable for the compiler to generate here:
public class Test<T> where T : struct
In the case you presented, where the compiler does not even know whether T is a value or reference type, there is similarly nothing to generate that would be valid for all possible types. A reference comparison would not be valid for value types and some sort of value comparison would be unexpected for reference types that do not overload.
Here is what you can do...
I have validated that both of these methods work for a generic comparison of reference and value types:
object.Equals(param, default(T))
or
EqualityComparer<T>.Default.Equals(param, default(T))
To do comparisons with the "==" operator you will need to use one of these methods:
If all cases of T derive from a known base class you can let the compiler know using generic type restrictions.
public void MyMethod<T>(T myArgument) where T : MyBase
The compiler then recognizes how to perform operations on MyBase and will not throw the "Operator '==' cannot be applied to operands of type 'T' and 'T'" error that you are seeing now.
Another option would be to restrict T to any type that implements IComparable.
public void MyMethod<T>(T myArgument) where T : IComparable
And then use the CompareTo method defined by the IComparable interface.
Try this:
if (EqualityComparer<T>.Default.Equals(myArgument, default(T)))
that should compile, and do what you want.
(Edited)
Marc Gravell has the best answer, but I wanted to post a simple code snippet I worked up to demonstrate it. Just run this in a simple C# console app:
public static class TypeHelper<T>
{
public static bool IsDefault(T val)
{
return EqualityComparer<T>.Default.Equals(obj,default(T));
}
}
static void Main(string[] args)
{
// value type
Console.WriteLine(TypeHelper<int>.IsDefault(1)); //False
Console.WriteLine(TypeHelper<int>.IsDefault(0)); // True
// reference type
Console.WriteLine(TypeHelper<string>.IsDefault("test")); //False
Console.WriteLine(TypeHelper<string>.IsDefault(null)); //True //True
Console.ReadKey();
}
One more thing: can someone with VS2008 try this as an extension method? I'm stuck with 2005 here and I'm curious to see if that would be allowed.
Edit: Here is how to get it working as an extension method:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// value type
Console.WriteLine(1.IsDefault());
Console.WriteLine(0.IsDefault());
// reference type
Console.WriteLine("test".IsDefault());
// null must be cast to a type
Console.WriteLine(((String)null).IsDefault());
}
}
// The type cannot be generic
public static class TypeHelper
{
// I made the method generic instead
public static bool IsDefault<T>(this T val)
{
return EqualityComparer<T>.Default.Equals(val, default(T));
}
}
To handle all types of T, including where T is a primitive type, you'll need to compile in both methods of comparison:
T Get<T>(Func<T> createObject)
{
T obj = createObject();
if (obj == null || obj.Equals(default(T)))
return obj;
// .. do a bunch of stuff
return obj;
}
Extension method based on accepted answer.
public static bool IsDefault<T>(this T inObj)
{
return EqualityComparer<T>.Default.Equals(inObj, default);
}
Usage:
private bool SomeMethod(){
var tValue = GetMyObject<MyObjectType>();
if (tValue == null || tValue.IsDefault()) return false;
}
Alternate with null to simplify:
public static bool IsNullOrDefault<T>(this T inObj)
{
if (inObj == null) return true;
return EqualityComparer<T>.Default.Equals(inObj, default);
}
Usage:
private bool SomeMethod(){
var tValue = GetMyObject<MyObjectType>();
if (tValue.IsNullOrDefault()) return false;
}
There is going to be a problem here -
If you're going to allow this to work for any type, default(T) will always be null for reference types, and 0 (or struct full of 0) for value types.
This is probably not the behavior you're after, though. If you want this to work in a generic way, you probably need to use reflection to check the type of T, and handle value types different than reference types.
Alternatively, you could put an interface constraint on this, and the interface could provide a way to check against the default of the class/struct.
I think you probably need to split this logic into two parts and check for null first.
public static bool IsNullOrEmpty<T>(T value)
{
if (IsNull(value))
{
return true;
}
if (value is string)
{
return string.IsNullOrEmpty(value as string);
}
return value.Equals(default(T));
}
public static bool IsNull<T>(T value)
{
if (value is ValueType)
{
return false;
}
return null == (object)value;
}
In the IsNull method, we're relying on the fact that ValueType objects can't be null by definition so if value happens to be a class which derives from ValueType, we already know it's not null. On the other hand, if it's not a value type then we can just compare value cast to an object against null. We could avoid the check against ValueType by going straight to a cast to object, but that would mean that a value type would get boxed which is something we probably want to avoid since it implies that a new object is created on the heap.
In the IsNullOrEmpty method, we're checking for the special case of a string. For all other types, we're comparing the value (which already know is not null) against it's default value which for all reference types is null and for value types is usually some form of zero (if they're integral).
Using these methods, the following code behaves as you might expect:
class Program
{
public class MyClass
{
public string MyString { get; set; }
}
static void Main()
{
int i1 = 1; Test("i1", i1); // False
int i2 = 0; Test("i2", i2); // True
int? i3 = 2; Test("i3", i3); // False
int? i4 = null; Test("i4", i4); // True
Console.WriteLine();
string s1 = "hello"; Test("s1", s1); // False
string s2 = null; Test("s2", s2); // True
string s3 = string.Empty; Test("s3", s3); // True
string s4 = ""; Test("s4", s4); // True
Console.WriteLine();
MyClass mc1 = new MyClass(); Test("mc1", mc1); // False
MyClass mc2 = null; Test("mc2", mc2); // True
}
public static void Test<T>(string fieldName, T field)
{
Console.WriteLine(fieldName + ": " + IsNullOrEmpty(field));
}
// public static bool IsNullOrEmpty<T>(T value) ...
// public static bool IsNull<T>(T value) ...
}
I use:
public class MyClass<T>
{
private bool IsNull()
{
var nullable = Nullable.GetUnderlyingType(typeof(T)) != null;
return nullable ? EqualityComparer<T>.Default.Equals(Value, default(T)) : false;
}
}
Just a hacky answer and as a reminder for myself.
But I find this quite helpful for my project.
The reason I write it like this is that because I don't want default integer 0 being marked as null if the value is 0
private static int o;
public static void Main()
{
//output: IsNull = False -> IsDefault = True
Console.WriteLine( "IsNull = " + IsNull( o ) + " -> IsDefault = " + IsDefault(o));
}
public static bool IsNull<T>(T paramValue)
{
if( string.IsNullOrEmpty(paramValue + "" ))
return true;
return false;
}
public static bool IsDefault<T>(T val)
{
return EqualityComparer<T>.Default.Equals(val, default(T));
}
Don't know if this works with your requirements or not, but you could constrain T to be a Type that implements an interface such as IComparable and then use the ComparesTo() method from that interface (which IIRC supports/handles nulls) like this:
public void MyMethod<T>(T myArgument) where T : IComparable
...
if (0 == myArgument.ComparesTo(default(T)))
There are probably other interfaces that you could use as well IEquitable, etc.
#ilitirit:
public class Class<T> where T : IComparable
{
public T Value { get; set; }
public void MyMethod(T val)
{
if (Value == val)
return;
}
}
Operator '==' cannot be applied to operands of type 'T' and 'T'
I can't think of a way to do this without the explicit null test followed by invoking the Equals method or object.Equals as suggested above.
You can devise a solution using System.Comparison but really that's going to end up with way more lines of code and increase complexity substantially.
I think you were close.
if (myArgument.Equals(default(T)))
Now this compiles, but will fail if myArgument is null, which is part of what I'm testing for. I can add an explicit null check like this:
You just need to reverse the object on which the equals is being called for an elegant null-safe approach.
default(T).Equals(myArgument);
How do I return null value from a generic method?
protected T ValueOrDefault<T>(IDataReader reader, int ordinalId)
{
Type t = typeof(reader.GetValue(ordinalId));
if (t.IsValueType){
//Struct. How do I return null?
} else {
//Class
//just return null
return default(T);
}
}
default(T) works in both cases.
default(T) does function in both cases, but its meaning is slightly different for value types. It literally returns the default value of the type. In the case of Method<int>, it will return 0, not null.
UPDATE: Given your method signature:
protected T ValueOrDefault<T>(IDataReader reader, int ordinalId)
You can't return Nullable<T> in the case of a value type and type T in the case of a reference type. That would have to be two different methods.
Obviously you can only return null if the return type is either Nullable<T> or a reference type. Normal value-types have no null.
For reference types default(T) is null, and for Nullable<T> it's null too. So you can use default(T) in both cases where null exists.
If the type is another value-type default(T) will not be null, but since there is no null that wouldn't make sense anyways.
It is not possible to simply have a method that has return type T if T is a reference-type/Nullable<T> and T? for normal value types.
One could try to define something like this, but it won't compile because the compiler doesn't understand that the generic constraints are mutually exclusive. It just doesn't consider generic constraints for that.
T? a<T>()
where T:struct
{
}
T a<T>()
where T:class
{
}
You need to make these methods different in some other way. Either by using different names or different parameters.
If you want to return T? if it's a value type, you have to use two separate methods. However, there is a complexity, in that methods can't differ only by their return type (there's also issues around the generic args not being part of a method signature). So you have to provide a 'stub' method parameter which the compiler uses to resolve which method to call:
public T MyMethod<T>(T stub) where T : class {
// ...
return null;
}
public T? MyMethod<T>(T? stub) where T : struct {
// ...
return null;
}
// this will then compile...
string s = MyMethod<string>(null);
int? i = MyMethod<int>(null);
It's not legal to return null for an unconstrained T value. Consider for instance if T is instantiated as a value type. In that case null would not be a legal value and hence the code is illegal.
What you're looking for is default(T). This will work for both value and reference types. For reference types it will produce null and for value types it will produce the zero initialized value.
In C# 9, it is possible to have a single method return null for reference and for nullable value types. Note that string and string? are exactly the same type but int and int? are different (Int32 and Nullable).
[TestMethod]
public void TestGenericNull()
{
static T? GetDefault<T>(bool wantNullable) => wantNullable ? default(T?) : default(T);
string? s1 = GetDefault<string>(false);
Assert.IsNull(s1);
string? s2 = GetDefault<string>(true);
Assert.IsNull(s2);
int? d1 = default(int);
Assert.AreEqual(d1, 0);
int? d2 = default(int?);
Assert.IsNull(d2);
int? n1 = GetDefault<int>(false);
Assert.AreEqual(n1, 0);
int? n2 = GetDefault<int>(true);
Assert.AreEqual(n2, 0); // Expected default(int?), i.e. Nullable<int> with no value.
int? n4 = GetDefault<int?>(false);
Assert.IsNull(n4);
int? n5 = GetDefault<int?>(true);
Assert.IsNull(n5);
}
To see why this isn't possible, try replacing T with a value type:
protected int ValueOrDefault<int>(IDataReader reader, int ordinalId)
{
Type t = typeof(reader.GetValue(ordinalId));
if (t.IsValueType){
//Struct. How do I return null?
} else {
//Class
//just return null
return default(int);
}
}
If the return type is int, you can't return null because it's not a valid value. The type of T would have to be nullable in the first place, in which case default(T) works.
You can use just return default without (T) at the end. C# 7.1 or above.
I have a generic method defined like this:
public void MyMethod<T>(T myArgument)
The first thing I want to do is check if the value of myArgument is the default value for that type, something like this:
if (myArgument == default(T))
But this doesn't compile because I haven't guaranteed that T will implement the == operator. So I switched the code to this:
if (myArgument.Equals(default(T)))
Now this compiles, but will fail if myArgument is null, which is part of what I'm testing for. I can add an explicit null check like this:
if (myArgument == null || myArgument.Equals(default(T)))
Now this feels redundant to me. ReSharper is even suggesting that I change the myArgument == null part into myArgument == default(T) which is where I started. Is there a better way to solve this problem?
I need to support both references types and value types.
To avoid boxing, the best way to compare generics for equality is with EqualityComparer<T>.Default. This respects IEquatable<T> (without boxing) as well as object.Equals, and handles all the Nullable<T> "lifted" nuances. Hence:
if(EqualityComparer<T>.Default.Equals(obj, default(T))) {
return obj;
}
This will match:
null for classes
null (empty) for Nullable<T>
zero/false/etc for other structs
How about this:
if (object.Equals(myArgument, default(T)))
{
//...
}
Using the static object.Equals() method avoids the need for you to do the null check yourself. Explicitly qualifying the call with object. probably isn't necessary depending on your context, but I normally prefix static calls with the type name just to make the code more soluble.
I was able to locate a Microsoft Connect article that discusses this issue in some detail:
Unfortunately, this behavior is by design and there is not an easy solution to enable use of with type parameters that may contain value types.
If the types are known to be reference types, the default overload of defined on object tests variables for reference equality, although a type may specify its own custom overload. The compiler determines which overload to use based on the static type of the variable (the determination is not polymorphic). Therefore, if you change your example to constrain the generic type parameter T to a non-sealed reference type (such as Exception), the compiler can determine the specific overload to use and the following code would compile:
public class Test<T> where T : Exception
If the types are known to be value types, performs specific value equality tests based on the exact types used. There is no good "default" comparison here since reference comparisons are not meaningful on value types and the compiler cannot know which specific value comparison to emit. The compiler could emit a call to ValueType.Equals(Object) but this method uses reflection and is quite inefficient compared to the specific value comparisons. Therefore, even if you were to specify a value-type constraint on T, there is nothing reasonable for the compiler to generate here:
public class Test<T> where T : struct
In the case you presented, where the compiler does not even know whether T is a value or reference type, there is similarly nothing to generate that would be valid for all possible types. A reference comparison would not be valid for value types and some sort of value comparison would be unexpected for reference types that do not overload.
Here is what you can do...
I have validated that both of these methods work for a generic comparison of reference and value types:
object.Equals(param, default(T))
or
EqualityComparer<T>.Default.Equals(param, default(T))
To do comparisons with the "==" operator you will need to use one of these methods:
If all cases of T derive from a known base class you can let the compiler know using generic type restrictions.
public void MyMethod<T>(T myArgument) where T : MyBase
The compiler then recognizes how to perform operations on MyBase and will not throw the "Operator '==' cannot be applied to operands of type 'T' and 'T'" error that you are seeing now.
Another option would be to restrict T to any type that implements IComparable.
public void MyMethod<T>(T myArgument) where T : IComparable
And then use the CompareTo method defined by the IComparable interface.
Try this:
if (EqualityComparer<T>.Default.Equals(myArgument, default(T)))
that should compile, and do what you want.
(Edited)
Marc Gravell has the best answer, but I wanted to post a simple code snippet I worked up to demonstrate it. Just run this in a simple C# console app:
public static class TypeHelper<T>
{
public static bool IsDefault(T val)
{
return EqualityComparer<T>.Default.Equals(obj,default(T));
}
}
static void Main(string[] args)
{
// value type
Console.WriteLine(TypeHelper<int>.IsDefault(1)); //False
Console.WriteLine(TypeHelper<int>.IsDefault(0)); // True
// reference type
Console.WriteLine(TypeHelper<string>.IsDefault("test")); //False
Console.WriteLine(TypeHelper<string>.IsDefault(null)); //True //True
Console.ReadKey();
}
One more thing: can someone with VS2008 try this as an extension method? I'm stuck with 2005 here and I'm curious to see if that would be allowed.
Edit: Here is how to get it working as an extension method:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
// value type
Console.WriteLine(1.IsDefault());
Console.WriteLine(0.IsDefault());
// reference type
Console.WriteLine("test".IsDefault());
// null must be cast to a type
Console.WriteLine(((String)null).IsDefault());
}
}
// The type cannot be generic
public static class TypeHelper
{
// I made the method generic instead
public static bool IsDefault<T>(this T val)
{
return EqualityComparer<T>.Default.Equals(val, default(T));
}
}
To handle all types of T, including where T is a primitive type, you'll need to compile in both methods of comparison:
T Get<T>(Func<T> createObject)
{
T obj = createObject();
if (obj == null || obj.Equals(default(T)))
return obj;
// .. do a bunch of stuff
return obj;
}
Extension method based on accepted answer.
public static bool IsDefault<T>(this T inObj)
{
return EqualityComparer<T>.Default.Equals(inObj, default);
}
Usage:
private bool SomeMethod(){
var tValue = GetMyObject<MyObjectType>();
if (tValue == null || tValue.IsDefault()) return false;
}
Alternate with null to simplify:
public static bool IsNullOrDefault<T>(this T inObj)
{
if (inObj == null) return true;
return EqualityComparer<T>.Default.Equals(inObj, default);
}
Usage:
private bool SomeMethod(){
var tValue = GetMyObject<MyObjectType>();
if (tValue.IsNullOrDefault()) return false;
}
There is going to be a problem here -
If you're going to allow this to work for any type, default(T) will always be null for reference types, and 0 (or struct full of 0) for value types.
This is probably not the behavior you're after, though. If you want this to work in a generic way, you probably need to use reflection to check the type of T, and handle value types different than reference types.
Alternatively, you could put an interface constraint on this, and the interface could provide a way to check against the default of the class/struct.
I think you probably need to split this logic into two parts and check for null first.
public static bool IsNullOrEmpty<T>(T value)
{
if (IsNull(value))
{
return true;
}
if (value is string)
{
return string.IsNullOrEmpty(value as string);
}
return value.Equals(default(T));
}
public static bool IsNull<T>(T value)
{
if (value is ValueType)
{
return false;
}
return null == (object)value;
}
In the IsNull method, we're relying on the fact that ValueType objects can't be null by definition so if value happens to be a class which derives from ValueType, we already know it's not null. On the other hand, if it's not a value type then we can just compare value cast to an object against null. We could avoid the check against ValueType by going straight to a cast to object, but that would mean that a value type would get boxed which is something we probably want to avoid since it implies that a new object is created on the heap.
In the IsNullOrEmpty method, we're checking for the special case of a string. For all other types, we're comparing the value (which already know is not null) against it's default value which for all reference types is null and for value types is usually some form of zero (if they're integral).
Using these methods, the following code behaves as you might expect:
class Program
{
public class MyClass
{
public string MyString { get; set; }
}
static void Main()
{
int i1 = 1; Test("i1", i1); // False
int i2 = 0; Test("i2", i2); // True
int? i3 = 2; Test("i3", i3); // False
int? i4 = null; Test("i4", i4); // True
Console.WriteLine();
string s1 = "hello"; Test("s1", s1); // False
string s2 = null; Test("s2", s2); // True
string s3 = string.Empty; Test("s3", s3); // True
string s4 = ""; Test("s4", s4); // True
Console.WriteLine();
MyClass mc1 = new MyClass(); Test("mc1", mc1); // False
MyClass mc2 = null; Test("mc2", mc2); // True
}
public static void Test<T>(string fieldName, T field)
{
Console.WriteLine(fieldName + ": " + IsNullOrEmpty(field));
}
// public static bool IsNullOrEmpty<T>(T value) ...
// public static bool IsNull<T>(T value) ...
}
I use:
public class MyClass<T>
{
private bool IsNull()
{
var nullable = Nullable.GetUnderlyingType(typeof(T)) != null;
return nullable ? EqualityComparer<T>.Default.Equals(Value, default(T)) : false;
}
}
Just a hacky answer and as a reminder for myself.
But I find this quite helpful for my project.
The reason I write it like this is that because I don't want default integer 0 being marked as null if the value is 0
private static int o;
public static void Main()
{
//output: IsNull = False -> IsDefault = True
Console.WriteLine( "IsNull = " + IsNull( o ) + " -> IsDefault = " + IsDefault(o));
}
public static bool IsNull<T>(T paramValue)
{
if( string.IsNullOrEmpty(paramValue + "" ))
return true;
return false;
}
public static bool IsDefault<T>(T val)
{
return EqualityComparer<T>.Default.Equals(val, default(T));
}
Don't know if this works with your requirements or not, but you could constrain T to be a Type that implements an interface such as IComparable and then use the ComparesTo() method from that interface (which IIRC supports/handles nulls) like this:
public void MyMethod<T>(T myArgument) where T : IComparable
...
if (0 == myArgument.ComparesTo(default(T)))
There are probably other interfaces that you could use as well IEquitable, etc.
#ilitirit:
public class Class<T> where T : IComparable
{
public T Value { get; set; }
public void MyMethod(T val)
{
if (Value == val)
return;
}
}
Operator '==' cannot be applied to operands of type 'T' and 'T'
I can't think of a way to do this without the explicit null test followed by invoking the Equals method or object.Equals as suggested above.
You can devise a solution using System.Comparison but really that's going to end up with way more lines of code and increase complexity substantially.
I think you were close.
if (myArgument.Equals(default(T)))
Now this compiles, but will fail if myArgument is null, which is part of what I'm testing for. I can add an explicit null check like this:
You just need to reverse the object on which the equals is being called for an elegant null-safe approach.
default(T).Equals(myArgument);