Implicit cast dynamic to DateTime? and op_Equality - c#

I have my own dynamic object which have to be comparable with primitive types. I defined implicit cast operators for all types I want to compare. For most of primitive types like int, short, bool, decimal implementing cast to nullable version of this types is enough for successful comparing, but not for DateTime. Did I missed some significant difference between DateTime and decimal or is it error in dynamic implementation?
class MyDynamic : DynamicObject
{
public static implicit operator decimal?(MyDynamic nullable)
{
return null;
}
public static implicit operator DateTime?(MyDynamic x)
{
return null;
}
//public static implicit operator DateTime(MyDynamic x)
//{
// return DateTime.MinValue;
//}
}
[Fact]
public void FactMethodName()
{
dynamic my = new MyDynamic();
dynamic date = DateTime.Now;
dynamic dec = 1m;
Assert.False(dec == my);
// throws
Assert.False(date == my);
}
If implicit cast is not defined error message is:
System.InvalidOperationExceptionThe operands for operator 'Equal' do not match the parameters of method 'op_Equality'.
stack trace is:
System.InvalidOperationExceptionThe operands for operator 'Equal' do not match the parameters of method 'op_Equality'.
at System.Linq.Expressions.Expression.GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, Boolean liftToNull)
at System.Linq.Expressions.Expression.Equal(Expression left, Expression right, Boolean liftToNull, MethodInfo method)
at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.GenerateUserDefinedBinaryOperator(EXPRCALL pExpr)
at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.VisitCALL(EXPRCALL pExpr)
at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Dispatch(EXPR pExpr)
at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Visit(EXPR pExpr)
at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.GenerateLambda(EXPRCALL pExpr)
at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.VisitCALL(EXPRCALL pExpr)
at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Dispatch(EXPR pExpr)
at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Visit(EXPR pExpr)
at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.Rewrite(TypeManager typeManager, EXPR pExpr, IEnumerable`1 listOfParameters)
at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.CreateExpressionTreeFromResult(IEnumerable`1 parameters, ArgumentObject[] arguments, Scope pScope, EXPR pResult)
at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, ref DynamicMetaObject deferredBinding)
at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, ref DynamicMetaObject deferredBinding)
at Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable`1 args, IEnumerable`1 arginfos, DynamicMetaObject onBindingError)
at Microsoft.CSharp.RuntimeBinder.CSharpBinaryOperationBinder.FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion)
at System.Dynamic.BinaryOperationBinder.FallbackBinaryOperation(DynamicMetaObject target, DynamicMetaObject arg)
at System.Dynamic.DynamicMetaObject.BindBinaryOperation(BinaryOperationBinder binder, DynamicMetaObject arg)
at System.Dynamic.BinaryOperationBinder.Bind(DynamicMetaObject target, DynamicMetaObject[] args)
at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
at System.Runtime.CompilerServices.CallSiteBinder.BindCore(CallSite`1 site, Object[] args)
at System.Dynamic.UpdateDelegates.UpdateAndExecute2<T0,T1,TRet>(CallSite site, T0 arg0, T1 arg1)
In most cases my custom dynamic should act almost as null, so casting to value type is unwanted.

defining operator == keep code simpler.
public static bool operator ==(MyDynamic lhs, object rhs)
{
if (rhs is MyDynamic)
return lhs.Equals(rhs);
else
return false;
}
public static bool operator !=(MyDynamic lhs, object rhs)
{
if (rhs is MyDynamic)
return !lhs.Equals(rhs);
else
return true;
}
public static bool operator ==(object lhs, MyDynamic rhs)
{
if (lhs is MyDynamic)
return lhs.Equals(rhs);
else
return false;
}
public static bool operator !=(object lhs, MyDynamic rhs)
{
if (lhs is MyDynamic)
return !lhs.Equals(rhs);
else
return true;
}
EDIT
I explicitly implement both (MyDynamic == object) and (object == MyDynamic). because overriding TryBinaryOperation() couldn't caught (object == MyDynamic) case.
public override bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result)
{
if (binder.Operation == System.Linq.Expressions.ExpressionType.Equal) { ... }
return base.TryBinaryOperation(binder, arg, out result);
}

Related

How to perform a null check in an equality operator overload

I've written a simple class that wraps an XElement. I want to pass through equality operations to the wrapped instance. So I wrote this:
public class XmlWrapper
{
protected readonly XElement _element;
public XmlWrapper(XElement element)
{
_element = element;
}
static public bool operator == (XmlWrapper lhs, XmlWrapper rhs)
{
return lhs._element.Equals(rhs._element);
}
static public bool operator != (XmlWrapper lhs, XmlWrapper rhs)
{
return !(lhs == rhs);
}
}
This seems straightforward, but actually it throws an exception for a very simple null check:
XmlWrapper wrapper = new XmlWrapper(someElement);
XmlWrapper nullWrapper = null;
if (wrapper != nullWrapper) Console.WriteLine("Wrapper is not null"); //This line throws
It's because the equality operator is receiving null for one of its arguments and therefore can't retrieve the wrapped XElement. So the obvious thought is to add a null check, like this:
static public bool operator == (XmlWrapper lhs, XmlWrapper rhs)
{
if (lhs == null && rhs == null) return true;
if (lhs == null || rhs == null) return false;
return lhs._element.Equals(rhs._element);
}
However, this results infinite recursion, because the == operator calls the == operator again.
If this were any other kind of method, I'd just call the base, but that doesn't work with an operator, e.g. you can't write
if (lhs base.== rhs)
So how do I get around this? Is there some way to call the base == operator from within the overloaded operator body? Or some other way to perform the null check without using ==?
Here is the code on DotNetFiddle.
public static bool operator == (XmlWrapper lhs, XmlWrapper rhs)
{
if (Object.ReferenceEquals(lhs, null) && Object.ReferenceEquals(rhs, null))
{
return true;
}
if (Object.ReferenceEquals(lhs, null) || Object.ReferenceEquals(rhs, null))
{
return false;
}
return lhs._element.Equals(rhs._element);
}
This should provide the desired behavior.
Also note that if overriding equality you need to override GetHashCode
public class XmlWrapper : IEquatable<XmlWrapper> {
protected readonly XElement _element;
public XmlWrapper(XElement element) {
_element = element ?? throw new ArgumentNullException(nameof(element));
}
static public bool operator ==(XmlWrapper lhs, XmlWrapper rhs) {
return Equals(lhs, rhs);
}
static public bool operator !=(XmlWrapper lhs, XmlWrapper rhs) {
return !Equals(lhs, rhs);
}
public override string ToString() {
return _element != null ? _element.ToString() : this.GetType().FullName;
}
public override int GetHashCode() {
return _element.GetHashCode();
}
public override bool Equals(object obj) {
return obj is XmlWrapper other && Equals(other);
}
public bool Equals(XmlWrapper other) {
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return _element.Equals(other._element);
}
}
It is worth noting this implementation is specific to reference types. Since XmlWrapper is a reference type.
You can shorten the code down to one line using the ternary operator:
static public bool operator == (XmlWrapper lhs, XmlWrapper rhs)
{
return lhs is null ? rhs is null : !(rhs is null) && lhs._element == rhs._element;
}
Which says, "if lhs is null, return true if rhs is null or false if rhs is not null. Otherwise (if lhs is not null), return true if rhs is not null and their elements are equals, else return false."
You can apply Elvis operator and null-coalescing operator as well to make it working.
static public bool operator == (XmlWrapper lhs, XmlWrapper rhs)
{
if (lhs?._element == null && rhs?._element == null) return true;
return lhs?._element?.Equals(rhs?._element) ?? false;
}

Implementing == operator in C# on explicit-interface implementation

I have defined a struct Coords that explicitly implements three interfaces, each defined like this:
public partial struct Coords
{
int ICoordsUser.X { get { return VectorUser.X; } }
int ICoordsUser.Y { get { return VectorUser.Y; } }
IntVector2D ICoordsUser.Vector { get { return VectorUser; }
set { VectorUser=value; } }
ICoordsCanon ICoordsUser.Canon { get { return this; } }
ICoordsUser ICoordsUser.Clone() { return NewUserCoords(VectorUser); }
string ICoordsUser.ToString() { return VectorUser.ToString(); }
IEnumerable<NeighbourCoords> ICoordsUser.GetNeighbours(Hexside hexsides) {
return GetNeighbours(hexsides);
}
int ICoordsUser.Range(ICoordsUser coords) { return Range(coords.Canon); }
}
with the names ICoordsCanon, ICoordsUser, and ICoordsCustom. Then I have defined Value Equality on the struct like so:
#region Value Equality
bool IEquatable<Coords>.Equals(Coords rhs) { return this == rhs; }
public override bool Equals(object rhs) {
return (rhs is Coords) && this == (Coords)rhs;
}
public static bool operator == (Coords lhs, Coords rhs) {
return lhs.VectorCanon == rhs.VectorCanon;
}
public static bool operator != (Coords lhs, Coords rhs) { return ! (lhs == rhs); }
public override int GetHashCode() { return VectorUser.GetHashCode(); }
bool IEqualityComparer<Coords>.Equals(Coords lhs, Coords rhs) { return lhs == rhs; }
int IEqualityComparer<Coords>.GetHashCode(Coords coords) {
return coords.GetHashCode();
}
#endregion
However, when I perform an equality comparison with the == operator between values of one of the interface types, as
if (coordsUser1 == userCoords2) { /* whatever */ }
a reference comparison using object.== is always performed. Does anyone know how I can force value equality onto the == operator in such a circumstance, using C#?
Thank you in advance for any thoughts or suggestions.
[Edit]
In the example above, both coordsUser1 and userCoords2 are instances of Coords stored in variables of type ICoordsUser, so it is not clear to me why the defined override of == is not being used.
Since you cannot define static members for an interface, you cannot define operators on an interface. Because operator overloading is resolved at compile-time, the compiler will not see any == operator that matches the signature given an interface type. Since Object defines the == operator for objects, and there is no better match at compile time, it will use that one.
There are three ways to solve this:
Cast the left-hand object to the type that defines the == operator.
return (Coords)coordsUser1 == userCoords2;
Use the normal Equals(object) method. However, this will box your struct.
return coordsUser1.Equals(userCoords2);
Force your interfaces to implement IEquatable<T>, and use the generic Equals(T) (which reduces boxing).
return coordsUser1.Equals(userCoords2);

overload == (and != , of course) operator, can I bypass == to determine whether the object is null

when I try to overload operator == and != in C#, and override Equal as recommended, I found I have no way to distinguish a normal object and null. For example, I defined a class Complex.
public static bool operator ==(Complex lhs, Complex rhs)
{
return lhs.Equals(rhs);
}
public static bool operator !=(Complex lhs, Complex rhs)
{
return !lhs.Equals(rhs);
}
public override bool Equals(object obj)
{
if (obj is Complex)
{
return (((Complex)obj).Real == this.Real &&
((Complex)obj).Imaginary == this.Imaginary);
}
else
{
return false;
}
}
But when I want to use
if (temp == null)
When temp is really null, some exception happens. And I can't use == to determine whether the lhs is null, which will cause infinite loop.
What should I do in this situation.
One way I can think of is to us some thing like Class.Equal(object, object) (if it exists) to bypass the == when I do the check.
What is the normal way to solve the problem?
Thank you.
You can use the following at the top of your Equals override:
if (Object.ReferenceEquals(obj, null))
return false;
The exception you are getting is probably a StackOverflowException because your == operator will cause infinite recursion.
EDIT:
If Complex is a struct you should not have any problems with NullReferenceExceptions. If Complex is a class you can change your implementation of the == and != operator overloads to avoid the exception (Laurent Etiemble already pointed this out in his answer):
public static bool operator ==(Complex lhs, Complex rhs)
{
return Equals(lhs, rhs);
}
public static bool operator !=(Complex lhs, Complex rhs)
{
return !Equals(lhs, rhs);
}
You should consider using the static Equals method in the operator overloads (which will call the instance Equals method):
public static bool operator ==(Complex lhs, Complex rhs)
{
return Equals(lhs, rhs);
}
public static bool operator !=(Complex lhs, Complex rhs)
{
return !Equals(lhs, rhs);
}
Note: You may also check for null in the Equals method.
You can also read the Object.Equals Topic on MSDN, which is a great source of samples.
public static bool operator ==(Complex lhs, Complex rhs)
{
if (Object.ReferenceEquals(lhs, null))
{
return Object.ReferenceEquals(rhs, null);
}
return lhs.Equals(rhs);
}
public static bool operator !=(Complex lhs, Complex rhs)
{
return !(lhs == rhs);
}
Poor man's unit test
Action<Complex, Complex> tester = (left, right) =>
{
Console.WriteLine(left == right);
Console.WriteLine(left != right);
Console.WriteLine(left == null);
Console.WriteLine(left != null);
Console.WriteLine("---");
};
tester(new Complex(), new Complex());
tester(null, new Complex());
tester(null, null);
tester(new Complex(), null);
I think you shoud test for null in the == operator implementation. Otherwise, when lhs is null, you'd call Complex(null).Equals (I don't know for C#, but in Java this would be a Nullpointer Exception)
To test for null, I suggest something like:
if (null == lhs && null == rhs) return true
else if (null == lhs) return false
else return lhs.Equals(rhs);
So Object.Equals will be called for all == comparisons above.
There is a better approach then using operators is and cast:
Complex c = obj as Complex;
return (c != null) && (c.Real == this.Real) && (c.Imaginary == this.Imaginary);
Here is a quick test concerning Equals operator override and comparing with null:
class Complex
{
public override bool Equals(object obj)
{
if (obj is Complex)
{
return true;
}
else
{
return false;
}
}
}
Debugging doesn't step into operator's body:
var b = (new Complex() == new Complex());

Why cast null before checking if object is equal to null?

I was looking through the "Domain Oriented N-Layered .NET 4.0 Sample App" project and ran across some code that I do not understand. In this project they often use syntax like the following to check arguments for null:
public GenericRepository(IQueryableContext context,ITraceManager traceManager)
{
if (context == (IQueryableContext)null)
throw new ArgumentNullException("context", Resources.Messages.exception_ContainerCannotBeNull);
Why would you cast null to the type of the object you are checking for null?
It's pointless in the example given.
While not applicable in this case, there is sometimes a need to cast null (or at least there was before default(T) was added. Consider the following:
void DoSomething(string x) {
...
}
void DoSomething(object x) {
...
}
DoSomething(null); // compiler can't infer the type
DoSomething((string)null); // string type is now explicit
DoSomething(default(string)); // same as previous
EDIT
Just thought of another case where you would have to do the cast when testing equality. If you had an object that had an overloaded == operator that allowed comparison with two reference types, comparing against null would be ambiguous. However because IQueryableContext is most likely an interface and interfaces cannot overload the == operator, I still don't see any valid reason to do it in the example you gave.
class CustomObject {
private string _id;
public CustomObject(string id) {
_id=id;
}
public static bool operator ==(CustomObject lhs, CustomObject rhs) {
if (ReferenceEquals(lhs, rhs)) { return true; }
if (ReferenceEquals(lhs, null)) { return false; }
if (ReferenceEquals(rhs, null)) { return false; }
return lhs._id == rhs._id;
}
public static bool operator !=(CustomObject lhs, CustomObject rhs) {
return !(lhs == rhs);
}
public static bool operator ==(CustomObject lhs, string rhs) {
if (ReferenceEquals(lhs, rhs)) { return true; }
if (ReferenceEquals(lhs, null)) { return false; }
if (ReferenceEquals(rhs, null)) { return false; }
return lhs._id == rhs;
}
public static bool operator !=(CustomObject lhs, string rhs) {
return !(lhs==rhs);
}
}
CustomObject o = null;
if (o == null) {
Console.WriteLine("I don't compile.");
}
I wouldn't do a cast. There's no reason for it in this case.
There is no reason to cast null in the given example. It might be for legibility... I don't know, I wouldn't do this =P
In some cases [which doesn't include the case covered in this topic] you have to cast to INullable before you can check to see if a variable is null. Otherwise, you have to use object==default(TypeOfObject)...

Handling comparisons with a custom boolean type?

I have a custom object that maps a boolean value from a legacy database to a C# bool (and back again).
My custom bool object looks like this:
public class S2kBool : IUserDefinedType {
public bool Value { get; set; }
public Type SupportedType { get { return typeof(string); } }
// These are the values used to represent booleans in the database
public const string TrueValue = "Y";
public const string FalseValue = "N";
public static S2kBool True {
get { return new S2kBool(true); }
}
public static S2kBool False {
get { return new S2kBool(false); }
}
public S2kBool() : this(false) { }
public S2kBool(bool value) {
this.Value = value;
}
// Called when a property of this type is populated from the database
public void FromSimpleDataType(object value) {
this.Value = value.ToString() == TrueValue;
}
// Called when a property of this type is inserted into the database
public object ToSimpleDataType() {
return this.Value ? TrueValue : FalseValue;
}
}
I would like to be able to do something like this:
public class TestObject {
public S2kBool IsActive = S2kBool.True;
}
TestObject tObj = new TestObject();
if (tObj.IsActive == S2kBool.True) {
// the above would evaluate to true
}
I've seen a few different methods for doing comparisons between objects, but I'm not sure of which one to use.
EDIT: Better yet, would it be possible to do something like the following and have C# treat the S2kBool object as an actual Boolean during comparison? It should also allow comparisons with other S2kBool objects, as well.
if (tObj.IsActive == true) { ... }
There are 2 things to look at; an implicit conversion operator (in S2kBool) to bool, or the true/false operators themselves...
true/false operators (note I prefer the implicit bool conversion myself):
public static bool operator true(S2kBool x) {
return x.Value;
}
public static bool operator false(S2kBool x) {
return !x.Value;
}
then you can use if(tObj.IsActive)
conversion operator:
public static implicit operator bool(S2kBool x) {
return x.Value;
}
works likewise
You might also add a conversion in the other direction:
public static implicit operator S2kBool(bool x)
{
return new S2kBool(x);
}
Then you can assign IsActive = false; etc
Finally, I wonder if this should be an immutable struct? It might be confusing if you expect this to behave like a value. For example, look at the last line here:
TestObject obj1 = new TestObject(),
obj2 = new TestObject();
obj1.IsActive = obj2.IsActive = S2kBool.True;
Console.WriteLine(obj1.IsActive);
Console.WriteLine(obj2.IsActive);
obj1.IsActive.Value = false;
Console.WriteLine(obj1.IsActive);
Console.WriteLine(obj2.IsActive); // what does this print?
This prints false, because both IsActive fields point to the same instance of S2kBool. If that was the intent, then fine. But if it was me, I'd make it immutable (whether class or struct). But since it doesn't really have any state other than a bool, I'd argue that this fits well as a struct.
To be honest, I'm not entirely sure why it is needed at all, when all the functionality could be done via static methods / etc.
Yes, you can do that. You would need to define equality operators and override the Equals method.
Here is an article about operator overloading:
http://www.csharphelp.com/archives/archive135.html
Here is an example of a type with overridden equality operators. You can do the same with assignment and conversion operators, making your type work seamlessly with the built-in bool type. (I took your example, shortened it a bit to keep the example short, and added the equality operators).
public struct S2kBool : IEquatable<bool>
{
public bool Value { get; set; }
public bool Equals(bool other)
{
return Value == other;
}
public override int GetHashCode()
{
return Value.GetHashCode();
}
public static bool operator ==(bool left, S2kBool right)
{
return right.Equals(left);
}
public static bool operator !=(bool left, S2kBool right)
{
return !(left == right);
}
public static bool operator ==(S2kBool left, bool right)
{
return left.Equals(right);
}
public static bool operator !=(S2kBool left, bool right)
{
return !(left == right);
}
}

Categories

Resources