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);
Related
I have a piece of code that attempts to cast and return an object called m_obj depending on a given generic type. Here is the code:
private IObject m_obj;
public bool TryGetAs<T>(out T value) where T :IObject
{
value = m_obj as T; // The type parameter 'T' cannot be used with the 'as' operator because it does not have a class type constraint nor a 'class' constraint
// value = (T)m_obj; This compiles!
if (value != null)
return true;
return false;
}
I know that if m_obj were a list, I could do this:
private readonly IList<Object> m_objects;
internal IList<T> Collect<T>() where T : IObject
{
return m_objects.OfType<T>().ToList();
}
However, I cannot figure out how to solve the problem in the first code example. Here is the original code again:
public interface IObject
{
}
This is my proposed solution:
public bool TryGetAs<T>(out T value) where T :IObject
{
value = default(T);
if (!(m_obj is T))
return false;
value = (T)m_obj;
return true;
}
I would like to know if my solution is correct and if there are any better or more elegant ways to solve this problem.
The as keyword works with reference types.
The compiler doesn't know that T is indeed a reference type, so it shouts at you and won't compile.
You can tell the compiler that it's a reference type by adding the class constraint before the IObject constraint. Now you can safely cast.
The as operator is reserved for reference types. If T is always a reference type, the solution is to add a class constraint to TryGetAs<T>. If T can also be a value type, this is not an option. In this case you can use the is operator:
public bool TryGetAs<T>(out T value) where T : IObject
{
if(m_obj is T)
{
value = (T)m_obj;
return true;
}
else
{
value = default(T);
return false;
}
}
In C# 7.0 you can simplify it like this (and improve performance since you don't need an is cast and then another type cast):
public bool TryGetAs<T>(out T value) where T : IObject
{
if(m_obj is T tValue)
{
value = tValue;
return true;
}
else
{
value = default(T);
return false;
}
}
public bool TryGetAs<T>(out T value) where T : class, IObject
{
value = m_obj as T;
return (value != null);
}
will act the same as your final solution, as well as likely being faster (since a null check is faster than an is check).
There is no benefit in not including the class modifier, if all of your IObject implementations are reference types (class) not value types (struct).
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);
I have two types sourceType and targetType and I need to write a method in C#, which checks if values of sourceType can be assigned to a variable of targetType. The signature of the function is MatchResultTypeAndExpectedType(Type sourceType, Type targetType).
The inheritance is covered by IsAssignableFrom. In the case of convertible types I thought to use CanConvertFrom, but, for example, if both types are numerical, then it always returns false.
A test, which I performed:
TypeConverter typeConverter = TypeDescriptor.GetConverter(typeof(Decimal));
Console.WriteLine("Int16 to Decimal - " + typeConverter.CanConvertFrom(typeof(Int16)));
Console.WriteLine("UInt16 to Decimal - " + typeConverter.CanConvertFrom(typeof(UInt16)));
typeConverter = TypeDescriptor.GetConverter(typeof(long));
Console.WriteLine("UInt16 to Int64 - " + typeConverter.CanConvertFrom(typeof(uint)));
typeConverter = TypeDescriptor.GetConverter(typeof(Double));
Console.WriteLine("UInt16 to Double - " + typeConverter.CanConvertFrom(typeof(UInt16)));
typeConverter = TypeDescriptor.GetConverter(typeof(String));
Console.WriteLine("UInt16 to String - " + typeConverter.CanConvertFrom(typeof(UInt16)));
The result is:
Int16 to Decimal - False
UInt16 to Decimal - False
UInt16 to Int64 - False
UInt16 to Double - False
UInt16 to String - False
[EDIT] So my question:
Is there a way in .NET to check whether a value of a given type can be assigned to a variable of another type without knowing values, e.g., whether implicit conversion will succeed? More specific requirements for implementation of MatchResultTypeAndExpectedType(Type sourceType, Type targetType):
Source and target types are not known at compile time, since their assemblies are loaded later.
No values or objects can be provided as input.
No objects of the types can be created in the implementation, since it is not allowed by the rest of the system. Values of value types can be created.
Only implicit conversion has to be checked.
It is known whether sourceType is value type. So the signature of the method can be like MatchResultTypeAndExpectedType(Type sourceType, Boolean isSourceValueType, Type targetType)
One way is to implement Implicit Numeric Conversions Table, but it will not cover other conversions or user defined conversions.
The problem about implicit/explicit conversions is that they're resolved at compile time. So there is (as far as I know) no simple runtime check. However, the dynamic implementation will pick them out and invoke them at runtime. You can (however ugly) create a class which will attempt to perform the conversion, catch the exception if it fails, and report whether or not it passed:
public class TypeConverterChecker<TFrom, TTo>
{
public bool CanConvert { get; private set; }
public TypeConverterChecker(TFrom from)
{
try
{
TTo to = (TTo)(dynamic)from;
CanConvert = true;
}
catch
{
CanConvert = false;
}
}
}
Given some classes like:
public class Foo
{
public static implicit operator Bar(Foo foo)
{
return new Bar();
}
public static implicit operator Foo(Bar bar)
{
return new Foo();
}
}
public class Bar
{
}
public class Nope
{
}
Usage:
Console.WriteLine((new TypeConverterChecker<Foo, Bar>(new Foo())).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<Bar, Foo>(new Bar())).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<Foo, Nope>(new Foo())).CanConvert); //False
And with the types you tested:
Console.WriteLine((new TypeConverterChecker<Int16, Decimal>(0)).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<UInt16, Decimal>(0)).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<UInt16, Int64>(0)).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<UInt16, Double>(0)).CanConvert); //True
Console.WriteLine((new TypeConverterChecker<UInt16, String>(0)).CanConvert); //False
Now I can imagine this can be modified to be more efficient (cache the result statically so subsequent lookups for the same TFrom, TTo combination don't have to attempt the conversion, for value-types ignore the need for an input instance to cast (just use default(TFrom)) and so on, but it should give you a start. It should be noted that you should not pass in null for TFrom from as all null conversions will pass (unless it's to a value-type)
You can also add a second try/catch to attempt using the Convert.ChangeType method and see if the types have defined IConvertable implementations that can be leveraged. (you may want to store this as a separate boolean flag so you know which type of conversion you need to perform later)
EDIT: If you don't know the types at compile time, you can take advantage of a bit of reflection to still leverage the conversion checker:
public static class TypeConverterChecker
{
public static bool Check(Type fromType, Type toType, object fromObject)
{
Type converterType = typeof(TypeConverterChecker<,>).MakeGenericType(fromType, toType);
object instance = Activator.CreateInstance(converterType, fromObject);
return (bool)converterType.GetProperty("CanConvert").GetGetMethod().Invoke(instance, null);
}
}
Your usage might be like:
object unknownObject = new Foo();
Type targetType = typeof(Bar);
Type sourceType = unknownObject.GetType();
Console.WriteLine(TypeConverterChecker.Check(sourceType, targetType, unknownObject));
targetType = typeof(Nope);
Console.WriteLine(TypeConverterChecker.Check(sourceType, targetType, unknownObject));
I implemented a solution, which partially satisfy my requirements. It is based on the answer from #ChrisSinclair, but does not require to provide an object of sourceType.
The implementation is:
public static Boolean MatchResultTypeAndExpectedType(Type sourceType, Type targetType) {
if (sourceType.IsValueType)
return Check(sourceType, targetType);
else
return targetType.IsAssignableFrom(sourceType);
}
public static bool Check(Type fromType, Type toType) {
Type converterType = typeof(TypeConverterChecker<,>).MakeGenericType(fromType, toType);
object instance = Activator.CreateInstance(converterType);
return (bool)converterType.GetProperty("CanConvert").GetGetMethod().Invoke(instance, null);
}
public class TypeConverterChecker<TFrom, TTo> {
public bool CanConvert { get; private set; }
public TypeConverterChecker() {
TFrom from = default(TFrom);
if (from == null)
if (typeof(TFrom).Equals(typeof(String)))
from = (TFrom)(dynamic)"";
else
from = (TFrom)Activator.CreateInstance(typeof(TFrom));
try {
TTo to = (dynamic)from;
CanConvert = true;
} catch {
CanConvert = false;
}
}
}
There are two problems with the solution:
It does not check if there are implicit conversions for non-value types (e.g., user defined). Since IsAssignableFrom is used, only inheritance is covered for non-value types.
It does not cover value types, which has null value as default and does not have default constructors, except String. String is explicitly covered.
You can always do this:
try
{
Convert.ChangeType(val, typeof(targetType));
return true;
}
catch (Exception)
{
return false;
}
I realize you don't have the instance, but you can easily and very cheaply create that with:
var val = Activator.CreateInstance(sourceType);
Note that Activator.CreateInstance() is extremely fast for value types.
Of course, for reference type just use Type.IsInstanceOfType().
I'm trying to write an Extension method for nullable Enums.
Like with this example:
// ItemType is an enum
ItemType? item;
...
item.GetDescription();
So I wrote this method which doesn't compile for some reason that I don't understand:
public static string GetDescription(this Enum? theEnum)
{
if (theEnum == null)
return string.Empty;
return GetDescriptionAttribute(theEnum);
}
I'm getting the following error on Enum?:
only non-nullable value type could be underlying of system.nullable
Why? Enum can not have the value null!
Update:
If have lots of enums, ItemType is just an example of one of them.
System.Enum is a class, so just drop the ? and this should work.
(By "this should work", I mean if you pass in a null-valued ItemType?, you'll get a null Enum in the method.)
public static string GetDescription(this Enum theEnum)
{
if (theEnum == null)
return string.Empty;
return GetDescriptionAttribute(theEnum);
}
enum Test { blah }
Test? q = null;
q.GetDescription(); // => theEnum parameter is null
q = Test.blah;
q.GetDescription(); // => theEnum parameter is Test.blah
You can simply make your extension method generic:
public static string GetDescription<T>(this T? theEnum) where T : struct
{
if (!typeof(T).IsEnum)
throw new Exception("Must be an enum.");
if (theEnum == null)
return string.Empty;
return GetDescriptionAttribute(theEnum);
}
Unfortunately, you cannot use System.Enum in a generic constraint, so the extension method will show for all nullable values (hence the extra check).
EDIT: C# 7.3 introduced new generic constraints which now allow restricting a generic argument to an enum, like so:
public static string GetDescription<T>(this T? theEnum) where T : Enum
{
if (theEnum == null)
return string.Empty;
return GetDescriptionAttribute(theEnum);
}
Thanks #JeppeStigNielsen for pointing that out.
You should use the actual enum type in your method signature:
public static string GetDescription(this ItemType? theEnum)
System.ValueType and System.Enum are not treated as value types (only types derived from them), so they are nullable (and you don't to specify them as nullable). Try it:
// No errors!
ValueType v = null;
Enum e = null;
You could also try this signature:
public static string GetDescription<T>(this T? theEnum) where T: struct
This also allows structs though, which might not be what you want. I think i remember some library that adds a type constraint of enum after compilation (C# doesn't allow it) though. Just need to find it...
EDIT: Found it:
http://code.google.com/p/unconstrained-melody/
Maybe better is add extra value to your enum and call it null :)
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.