Edit: I filed a bug report on microsoft connect::
https://connect.microsoft.com/VisualStudio/feedback/details/614234/delegate-createdelegate-allows-binding-functions-with-enum-parameters-to-the-enum-base-type#details
Consider the following thing:
public static Int32 Test(Int16 #short)
{
return #short;
}
and from calling code::
Func<Int16,Int32> test = Test; //valid method group conversion.
Func<Int16,StringComparison> test2 = Test; // doesn't compile, not valid method group conversion.
Func<Int16,StringComparison> test3 = test; // doesn't compile, invalid contra-variance.
Func<Int16,StringComparison> test4 = Delegate.CreateDelegate(typeof(Func<Int16,StringComparison>),test.Method) as Func<Int16,StringComparison>; // works fine.
Why can Delegate.CreateDelegate do this strange conversion that no other means of creating a function allows? Even worse, a somewhat more sensible conversion to say Int64 or Object both fail. I realize that StringComparison "extends" Int32, But I thought that was more of a compiler trick as enum's extend the Enum class.
Also, this conversion works for DynamicMethod.CreateDelegate, as well.
Edit just tried it with Nullable<Int32> it doesn't work, which is perplexing. I think the only "free" conversion is to Enum types to their underlying type, but why?
Note that this does not allow you to convert an int instance method (like GetHashCode) to an open method that takes the enum type, which is why I think this is a bug as the behavior is inconsistent.
Edit:
If we remove test2 and test3 line we can then test to see that the method,delegate, and the "illegal" delegate all work as expected.
Console.WriteLine(Test(0)); // prints 0
Console.WriteLine(test(0)); // prints 0
Console.WriteLine(test4(0)); //prints CurrentCulture
Edit:
Here is a very big abuse of this that I wrote in about 10 minutes. This creates an IEqualityComparer<T> for an TEnum, by basically grabbing the one for its an underlying type and then just wrapping the Equals, and HashCode and using this trick/abuse to convert the parameters to TEnums, rather than underlying type. If this is a bug I'd like to know so that I won't try to rely on this behavior.
class EnumComparer<TEnum> : EqualityComparer<TEnum> where TEnum : struct
{
static Func<TEnum, TEnum, bool> s_Equals;
static Func<TEnum, int> s_HashCode;
static EnumComparer<TEnum> s_default;
static EnumComparer()
{
if (!typeof(TEnum).IsEnum) throw new Exception("Not an enum type");
Type underlyingType = Enum.GetUnderlyingType(typeof(TEnum));
object equalityComparer = typeof(EqualityComparer<>).MakeGenericType(new[] { underlyingType }).GetProperty("Default").GetGetMethod().Invoke(null, null);
s_Equals = Delegate.CreateDelegate(typeof(Func<TEnum, TEnum, bool>), equalityComparer,equalityComparer.GetType().GetMethod("Equals", new[]{underlyingType,underlyingType})) as Func<TEnum,TEnum,bool>;
s_HashCode = Delegate.CreateDelegate(typeof(Func<TEnum, int>), equalityComparer, equalityComparer.GetType().GetMethod("GetHashCode", new[]{underlyingType})) as Func<TEnum, int>;
s_default = new EnumComparer<TEnum>();
}
public static new EnumComparer<TEnum> Default
{
get
{
return s_default;
}
}
public override bool Equals(TEnum x, TEnum y)
{
return s_Equals(x, y);
}
public override int GetHashCode(TEnum obj)
{
return s_HashCode(obj);
}
private EnumComparer()
{
}
}
This is not a bug. It is always possible to convert an integral value type to an enum like StringComparison. The compiler normally requires a cast but you are bypassing the compiler here. And just as in C#, there is no check to verify that the integral value actually represents one of the enumeration values.
Related
I'm experimenting with custom integer types and came across an interesting issue involving generics, implicit conversions, and 32 bit integers.
Below is a stripped down example of how to reproduce the problem. If I have two implicit methods that convert int to MyInt and vice versa, I get a compilation error which looks like C# can't resolve which generic type to use. And it only happens with int or uint. All other integer types work fine: sbyte,byte,short,ushort,long,ulong.
If I remove one of the implicit conversion methods, it also works fine. Something to do with circular implicit conversions?
using Xunit;
public class MyInt
{
public int Value;
//If I remove either one of the implicit methods below, it all works fine.
public static implicit operator int(MyInt myInt)
{
return myInt.Value;
}
public static implicit operator MyInt(int i)
{
return new MyInt() { Value = i };
}
public override bool Equals(object obj)
{
if (obj is MyInt myInt)
{
return this.Value == myInt.Value;
}
else
{
int other_int = (int)obj;
return Value == other_int;
}
}
}
Below is the test code showing the compilation errors I get when both implicit methods are defined.
public class Test
{
[Fact]
public void EqualityTest()
{
MyInt myInt = new MyInt();
myInt.Value = 4 ;
Assert.Equal(4, myInt.Value); //Always OK which makes sense
//Compile errors when both implicit methods defined:
// Error CS1503 Argument 1: cannot convert from 'int' to 'string',
// Error CS1503 Argument 2: cannot convert from 'ImplicitConversion.MyInt' to 'string'
Assert.Equal(4, myInt);
}
}
I believe C# is complaining about not being able to convert both types to string as that is the type of the last Xunit.Assert.Equal() overload and all the others failed to match:
//Xunit.Assert.Equal methods:
public static void Equal<T>(T expected, T actual);
public static void Equal(double expected, double actual, int precision);
public static void Equal<T>(T expected, T actual, IEqualityComparer<T> comparer);
public static void Equal(decimal expected, decimal actual, int precision);
public static void Equal(DateTime expected, DateTime actual, TimeSpan precision);
public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual, IEqualityComparer<T> comparer);
public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual);
public static void Equal(string expected, string actual, bool ignoreCase = false, bool ignoreLineEndingDifferences = false, bool ignoreWhiteSpaceDifferences = false);
public static void Equal(string expected, string actual);
I don't think I've made a mistake with the implicit conversions as I can make other similar examples create the same problem when used with 32 bit ints.
I'm testing in a .NET Core 3.0 project.
Any help would be appreciated. Thanks!
Clarification:
What I would like to know is why this only fails with 32 bit integers. Implicit conversions are working (confirmed with debugging) when the types are anything else like the example below using a long.
using Xunit;
public class MyLong
{
public long Value;
public static implicit operator long(MyLong myInt)
{
return myInt.Value;
}
public static implicit operator MyLong(long i)
{
return new MyLong() { Value = i };
}
public override bool Equals(object obj)
{
if (obj is MyLong myInt)
{
return this.Value == myInt.Value;
}
else
{
long other_int = (long)obj;
return Value == other_int;
}
}
}
public class Test2
{
[Fact]
public void EqualityTest()
{
MyLong myLong = new MyLong();
myLong.Value = 4 ;
Assert.Equal(4, myLong); //NOTE! `4` is implicitly converted to a MyLong
//object for comparison. Confirmed with debugging.
}
}
Something to do with circular implicit conversions?
Yes (though, you've already demonstrated that much by showing that it works fine when one of the conversions is eliminated).
The reason this is happening with int, and not with other types, is that the type of your literal is int. This means that during overload resolution, the compiler can go either way: convert int to MyInt, or convert MyInt to int. Neither option is clearly "better" than the other, so neither of those conversions survive consideration.
Then, having ruled out the closest possible generic version of the method, of the remaining overloads available the only one left is the Equal(string, string) overload (the only other one left with just two parameters is the Equal<T>(IEnumerable<T>, IEnumerable<T>), which is "worse" than the Equal(string, string) overload according to the overload resolution rules). Having found exactly one method that is clearly "better" than any others, the compiler then tries to use that method with your parameters, which of course don't fit, causing the errors to be emitted.
On the other hand…
When you try to call Equal(4, myLong), you've got two incompatible types. A literal having type int, and the MyLong value. In this case, the compiler tries each parameter one by one and finds that when it uses the MyLong type as the type parameter, it is possible to promote the int literal to a long and then implicitly convert that to MyLong. But it can't go the other way. It's not possible to select int as the generic type parameter, because MyLong can't be implicitly converted to int. So in that case, there is a "better" overload to choose, and so it's chosen.
By explicitly specifying the literal's type, you can try different combinations and see this pattern at work. First, I prefer a simpler wrapper class to test with:
public class Wrapper<T>
{
public T Value;
public static implicit operator T(Wrapper<T> wrapper) => wrapper.Value;
public static implicit operator Wrapper<T>(T value) => new Wrapper<T> { Value = value };
}
Then try these:
Wrapper<int> w1 = new Wrapper<int> { Value = 4 };
Wrapper<long> w2 = new Wrapper<long> { Value = 4 };
Assert.Equal(4, w1); // error
Assert.Equal((short)4, w1); // no error
Assert.Equal(4, w2); // no error
Assert.Equal(4L, w2); // error
The only thing that makes int special is that that's the default type for the numeric literal. Otherwise, a type that wraps int works exactly the same as a type that wraps anything else. As long as a conversion is available only in one direction between the two parameters, everything's fine. But when the conversion is available in both directions, the compiler has no choice but to throw up its hands and give up.
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);
Under which circumstances would be (bool) mydata a valid cast when mydata type is System.Object?
I.e., obviously it would be a valid cast if the actual or unrderlying type is a boolean.
But would it be also a valid cast if the underlying type is int or maybe string? E.g.,
int value=1;
object mydata=value;
if ((bool) value) { ... }
Actually I am wondering how explicit conversions work in C#. Is some kind of reflection used to check if any valid conversion exists even when dealing with object types?
An int is not a bool. Try it and find out what happens (InvalidCastException).
One should note that most of the primitive types explicitly implement IConvertible, so you can get the cast you want this way:
int a = 37 ;
object b = a ;
bool c = (b as IConvertible) != null && (b as IConvertible).ToBoolean(null);
In the case of an int → bool conversion like this, the conversion is done in the usual C-like manner: zero is false and non-zero is true. Worth noting that this behaviour is at odds with formal logic wherein falsity is multi-valued, being all that is not true and truth uni-valued. But I digress.
As far as custom conversions go, whether implicit or explicit, all you're doing is providing custom methods that are recognized as operators by the compiler. The how of the conversion, of course, is up to you and your implementation. Here, the class Foo knows how to convert itself [explicitly] to an instance of class Bar:
class Foo
{
public static explicit operator Bar(Foo x)
{
// your implementation here
throw new NotImplementedException();
}
}
And here, class Bar knows how to [explicitly] convert itself to an int and to [implicitly] convert itself to a Foo:
class Bar
{
public static explicit operator int(Bar x)
{
// your implementation here
throw new NotImplementedException();
}
public static implicit operator Foo(Bar x)
{
// your implementation here
throw new NotImplementedException();
}
}
When you start mixing stuff up, the compiler will figure out what conversion method(s) are applicable (or not) and resolve them. You'll either get a compile error about the conversion or the compile will have selected a conversion method to be invoked at runtime.
At runtime, of course, it is possible that an exception might be thrown in the course of the conversion.
Paraphrased from Eric Lippert's blog:
http://blogs.msdn.com/b/ericlippert/archive/2009/03/19/representation-and-identity.aspx
The C# cast operator is used for identity preserving conversions (e.g. interpret this reference to base class as a reference to derived class) and identity destroying conversions (e.g. convert this int to a double). A single use of the cast operator is only allowed to invoke one of these.
Since you boxed an int, the only thing that the int may be unboxed to is int (this is an identity preserving case). Once it is unboxed to int, it may be converted (in the identity destroying case) to bool.
That is:
int iii = 123;
object ooo = iii; // Box the int
bool bbb = (bool) iii; // Perfectly legal
bool jjj = (bool) (int) ooo; // Perfectly legal
bool kkk = (bool) ooo; // Invalid cast exception
First thing first: a cast of an object to bool is valid only when the object is a reference type wrapper for the bool or Nullable<bool> type:
bool val1 = true;
object mydata1=val1;
if ((bool) val1) { ... } // This is valid
bool? val2 = false;
object mydata2=val2;
if ((bool) val2) { ... } // This is valid too
When you cast an object to another type in C#, the runtime has enough information about the runtime type of the object being typecast to validate the operation, and throw an InvalidCastException when the cast is invalid.
In situations when the dynamic type of the object at runtime does not match the type to which you would like it to cast, you should use methods of the Convert class.
Probably your best course of action to reduce exceptions and make casting easy is to use the as operator and a nullable boolean bool?.
object test1 = 1;
object test2 = true;
var testBool1 = test1 as bool?;
var testBool2 = test2 as bool?;
if (testBool1.HasValue)
{
// test1 is a boolean
bool mybool = testBool1.Value;
}
if (testBool2.HasValue)
{
// test2 is a boolean
bool mybool = testBool2.Value;
}
use this code for convert object to Boolean
var t = propInfo.GetValue(item, null);
bool state = Convert.ToBoolean(t);
use this code for convert object to Boolean
var t = propInfo.GetValue(item, null);
bool state = Convert.ToBoolean(t);
How can I implement a struct so that the following cast can be performed?
var a = new StatusedValue<double>(1, false);
var b = (StatusedValue<int>)a;
My implementation should behave similarly to Nullable<T>, which works fine. However, this code fails with System.InvalidCastException:
public struct StatusedValue<T> where T : struct
{
public StatusedValue(T value) : this(value, true)
{
}
public StatusedValue(T value, bool isValid)
{
this.value = value;
this.isValid = isValid;
}
private T value;
private bool isValid;
public static implicit operator StatusedValue<T>(T value)
{
return new StatusedValue<T>(value);
}
public static explicit operator T(StatusedValue<T> value)
{
return value.value;
}
}
Result:
Unable to cast object of type 'StatusedValue`1[System.Double]' to type
'StatusedValue`1[System.Int32]'.
This works for Nullable<T> types because they get special treatment from the compiler. This is called a "lifted conversion operator", and you cannot define your own.
From section 6.4.2 of the C# Specification:
6.4.2 Lifted conversion operators
Given a user-defined conversion operator that converts from a non-nullable value type S to a
non-nullable value type T, a lifted conversion operator exists that
converts from S? to T?. This lifted conversion operator performs an
unwrapping from S? to S followed by the user-defined conversion from S
to T followed by a wrapping from T to T?, except that a null valued
S? converts directly to a null valued T?. A lifted conversion operator
has the same implicit or explicit classification as its underlying
user-defined conversion operator. The term “user-defined conversion”
applies to the use of both user-defined and lifted conversion
operators
If you're happy calling a method, try
public StatusedValue<U> CastValue<U>() where U : struct
{
return new StatusedValue<U>((U)Convert.ChangeType(value, typeof(U)), isValid);
}
This will unfortunately throw at runtime rather than compile time if T cannot be converted to U.
Edit: As pointed out below, if you constrain to IConvertible as well as/instead of struct then every conversion is theoretically possible at compile time, and you'll only get a runtime failure because of bad runtime values.
Nullables are specially handled by the compiler, I don't know if this is the case here.
Your operators would allow this:
StatusedValue<int> b = (int)a;
which is probably not what you want, because IsValid is not copied this way.
You could implement an extension method like this:
public static StatusedValue<TTarget> Cast<TSource, TTarget>(this StatusedValue<TSource> source)
where TTarget : struct
where TSource : struct
{
return new StatusedValue<TTarget>(
(TTarget)Convert.ChangeType(
source.Value,
typeof(TTarget)),
source.IsValid);
}
b = a.Cast<int>();
But the compiler cannot check if the types are compatible. ChangeType also returns an object, thus boxing your value.
The answer to why it's like this has already been posted and marked as the answer.
However, you can simplify the syntax to make it easier and clearer to do this while retaining compile-time type-safety.
Firstly, write a helper class to avoid having to specify redundant type parameters:
public static class StatusedValue
{
public static StatusedValue<T> Create<T>(T value, bool isValid = true) where T: struct
{
return new StatusedValue<T>(value, isValid);
}
}
Next you need to expose the underlying value with a Value property (otherwise you can't cast it from code).
Finally you can change your original code from this:
var a = new StatusedValue<double>(1, false);
var b = (StatusedValue<int>)a;
To this:
var a = StatusedValue.Create(1.0, false);
var b = StatusedValue.Create((int)a.Value, false);
where you are doing a simple cast on a.Value.
For a workaround, you will need to provide a way for converting from one underlying type to the other, since the compiler won't be able to figure that out:
public StatusedValue<TResult> To<TResult>(Func<T, TResult> convertFunc)
where TResult : struct {
return new StatusedValue<TResult>(convertFunc(value), isValid);
}
You can then do:
var a = new StatusedValue<double>(1, false);
var b = a.To(Convert.ToInt32);
With some reflection you could build a lookup table of the Convert methods, and lookup the right one based on the type arguments, and then you could default the conversion function to null and if it's not provided, try to lookup the correct conversion automatically. This would remove the clumsy Convert.ToInt32 part, and simply do var b = a.To<int>();
As Rawling points out, Convert.ChangeType can be used. This would make my method look like:
public StatusedValue<T2> To<T2>(Func<T, T2> convertFunc = null)
where T2 : struct {
return new StatusedValue<T2>(
convertFunc == null
? (T2)Convert.ChangeType(value, typeof(T2))
: convertFunc(value),
isValid
);
}
If you don't need a casting, you can add a method like this:
public StatusedValue<int> ConvertToStatusedInt() {
return new StatusedValue<int>(Convert.ToInt32(value), isValid);
}
As suggested in comment:
public StatusedValue<Q> ConvertTo<Q>() where Q:struct {
return new StatusedValue<Q>((Q)Convert.ChangeType(value, typeof(Q)), isValid);
}
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);