Explicit cast string to class fails in Equals - c#

As part of a website I'm working on, users may need to update partial information for each ticket submitted. When I test out a TryUpdateModel with this particular class which has an explicit operator to convert it to a string, I get an InvalidCastException. I've managed to isolate this exception down from all the previous MVC code to this:
Class
public class ConversionOperator
{
public ConversionOperator()
{
FullName = string.Empty;
}
public ConversionOperator(string fullName)
{
FullName = fullName;
}
public string FullName { get; set; }
public static explicit operator string(ConversionOperator item)
{
return item == null
? string.Empty
: item.FullName;
}
public static explicit operator ConversionOperator(string item)
{
return string.IsNullOrEmpty(item)
? new ConversionOperator()
: new ConversionOperator(item);
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
ConversionOperator other = (ConversionOperator) obj;
return FullName == other.FullName;
}
}
Unit Test
[TestMethod]
public void Verify_Conversion_To_String()
{
ConversionOperator first;
first = new ConversionOperator("Henry Beauford Autumnbottom Elderberry McClatchen");
Assert.AreEqual(first.FullName, (string) first); // passes
Assert.IsTrue(first.Equals("Henry Beauford Autumnbottom Elderberry McClatchen")); // throws exception
}
[TestMethod]
public void Verify_Conversion_From_String()
{
string name = "Henry Beauford Autumnbottom Elderberry McClatchen";
Assert.AreEqual((ConversionOperator) name, new ConversionOperator(name));
}
The first Assert in Verify_Conversion_To_String passes, but the second one fails, throwing an InvalidCastException. It's clear that the .NET Framework knows obj is a string, but the explicit conversion isn't being called.
Changing from a cast to as ConversionOperator produces a null object, which isn't correct either.

It looks like you are passing in a String to your Equals method. If that's the case then it will fail the cast to ProperName.
What you will can do is create a different Equals method that takes a string (or several strings) and tests those against the ProperName properties to see if they'd match:
public bool Equals(string fullName, t1 middleNameOptions, t2 displayOptions)
{
return this.FullName == item.FullName
&& this.MiddleNameOptions == item.MiddleNameOptions
&& this.DisplayOptions == item.DisplayOptions;
}

I solved the problem by implementing IEquatable<string>:
public bool Equals(string other)
{
ConversionOperator item = new ConversionOperator(other);
return this.Equals(item);
}
Now the unit tests pass, and I'm going to go bang my head on the wall until I forget that I asked this question.

To prevent the exception from occurring, you can call the object's ToString() method:
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
ProperName item = (ConversionOperator) obj.ToString();
return FullName == item.FullName
&& MiddleNameOptions == item.MiddleNameOptions
&& DisplayOptions == item.DisplayOptions;
}
Notes:
In order for the TryUpdateModel method to bind a model to the given prefix (of form data), you will likely need an implicit cast.
If you look at the source for the Controller class, can see that under the hood, the DefaultModelBinder is used.
The DefaultModelBinder has limitations, and is generally better with a specialized model, which is then mapped to your domain model (perhaps with manually written code, or with AutoMapper)
If you can't change your approach, then I suggest creating a Custom Model Binder which will give you direct control of how the form is translated to the model.

Related

Function to return a function that returns a function, etc

Is it possible to define a function in a way that it basically returns itself as a delegate?
For example, if this was valid syntax:
public class Scrub
{
public NotNull NotNull<T>(T value, string name)
{
if (value == null) throw new ArgumentNullException(name);
return NotNull;
}
}
Then I could chain method calls together like this.
Scrub.NotNull(param1, nameof(param1))(param2, nameof(param2)(param3, nameof(param3));
Well yes, you can, with your own delegate declaration:
delegate SelfReturner<T> SelfReturner<T>(T value, string name);
static SelfReturner<T> NotNull<T>(T value, string name)
{
if (value == null) throw new ArgumentNullException(name);
return NotNull;
}
... but it doesn't seem useful to me. Any reason you really want to do this, rather than just making three separate calls? For example, I have a Preconditions.CheckNotNull which returns the non-null value - I find that a lot more useful than this looks, to be honest.
As noted in comments, the above only works if all the parameters are of the same type (or all implicitly convertible to the type of the first parameter). An alternative to allow chaining with a bit more work would be to use a singleton instance with a generic method:
public sealed class NullChecker
{
public static NullChecker Instance { get; } = new NullChecker();
private NullChecker() {}
public static NullChecker Scrub<T>(T value, string paramName) where T : class
{
if (value == null)
{
throw new ArgumentNullException(paramName);
}
return this;
}
}
Use as:
NullChecker.Instance.Scrub(param1, nameof(param1))
.Scrub(param2, nameof(param2))
.Scrub(param3, nameof(param3));
With two separate methods, one static and one not (but with different names) you could remove the Instance part. For example:
NullChecker.Scrub(param1, nameof(param1))
.And(param2, nameof(param2))
.And(param3, nameof(param3));
If you make it an extension method:
public static class Scrub
{
public static T NotNull<T, U>(this T value, U property, string name)
{
if (property == null) throw new ArgumentNullException(name);
return value;
}
}
You can do:
test.NotNull(test.A, nameof(testA.A).NotNull(test.B, nameof(testA.B)));
Not quite what you wanted.

Comparison to null evaluates to true for both expr == null and expr != null

I am seeing something very strange, which I cannot explain. I am guessing some edge case of C# which I am not familiar with, or a bug in the runtime / emitter?
I have the following method:
public static bool HistoryMessageExists(DBContext context, string id)
{
return null != context.GetObject<HistoryMessage>(id);
}
While testing my app, I see it is misbehaving - it is returning true for objects I know do not exist in my db. So I stopped at the method and in Immediate, I ran the following:
context.GetObject<HistoryMessage>(id)
null
null == context.GetObject<HistoryMessage>(id)
true
null != context.GetObject<HistoryMessage>(id)
true
GetObject is defined like so:
public T GetObject<T>(object pk) where T : DBObject, new()
{
T rv = Connection.Get<T>(pk);
if (rv != null)
{
rv.AttachToContext(this);
rv.IsInserted = true;
}
return rv;
}
Interestingly, when casting the expression to object, the comparison is evaluated correctly:
null == (object)context.GetObject<HistoryMessage>(id)
true
null != (object)context.GetObject<HistoryMessage>(id)
false
There is no equality operator overriding.
Edit: It turns out there is an operator overload, which was incorrect. But then why would the equality evaluate correctly in the internal method generic GetObject, where rv is of type HistoryMessage in this case.
public class HistoryMessage : EquatableIdentifiableObject
{
public static bool HistoryMessageExists(DBContext context, string id)
{
var rv = context.GetObject<HistoryMessage>(id);
bool b = rv != null;
return b;
}
public static void AddHistoryMessage(DBContext context, string id)
{
context.InsertObject(new HistoryMessage { Id = id });
}
}
public abstract partial class EquatableIdentifiableObject : DBObject, IObservableObject
{
public event PropertyChangedEventHandler PropertyChanged;
[PrimaryKey]
public string Id { get; set; }
//...
}
public abstract partial class EquatableIdentifiableObject
{
//...
public static bool operator ==(EquatableIdentifiableObject self, EquatableIdentifiableObject other)
{
if (ReferenceEquals(self, null))
{
return ReferenceEquals(other, null);
}
return self.Equals(other);
}
public static bool operator !=(EquatableIdentifiableObject self, EquatableIdentifiableObject other)
{
if (ReferenceEquals(self, null))
{
return !ReferenceEquals(other, null);
}
return !self.Equals(other);
}
}
public abstract class DBObject
{
[Ignore]
protected DBContext Context { get; set; }
[Ignore]
internal bool IsInserted { get; set; }
//...
}
What is going on here?
As you already clarified, the == operator failed for your type because you had an overload that was incorrect.
When casting to object, the == operator worked correctly since it was object's implementation of == that was used and not EquatableIdentifiableObject's.
In the method GetObject the operator evaluates correctly because it is not EquatableIdentifiableObject's implementation of == that is being used. In C# generics are resolved at run-time (at least in the sense that is relevant here) and not at compile time. Note that == is static and not virtual. So the type T is resolved at run-time but the call to == has to be resolved at compile time. At compile time when the compiler resolves == it will not know to use EquatableIdentifiableObject's implementation of ==. Since the type T has this constraint: where T : DBObject, new(), DBObject's implementation (if any) will be used. If DBObject does not define == then the implementaion of the first base class that does so (up to object) will be used.
A few more comments about EquatableIdentifiableObject's implementation of ==:
You could replace this part:
if (ReferenceEquals(self, null))
{
return ReferenceEquals(other, null);
}
with:
// If both are null, or both are the same instance, return true.
if (object.ReferenceEquals(h1, h2))
{
return true;
}
It would be more robust to replace
public static bool operator !=(EquatableIdentifiableObject self, EquatableIdentifiableObject other)
{
...
}
with:
public static bool operator !=(EquatableIdentifiableObject self, EquatableIdentifiableObject other)
{
return !(self == other);
}
The way you define the signature for == is slightly misleading. The first parameter is named self and the second is named other. That would be ok if == was an instance method. Since it is a static method, the name self is a bit misleading. Better names would be o1 and o2 or something along this line so that the two operands are treated on a more equal footing.
There can be several overloads of operator ==(...) as you now know. Some of them can be C# built-in overloads, and others can be user-defined operators.
If you hold the mouse over the != or == symbol in Visual Studio, it will show you what overload is chosen by overload resolution (up till VS2013 it would only show it if the chosen overload was actually a user-defined one, in VS2015 it will show it in all cases I believe).
The binding of == (i.e. which overload to call) is fixed statically at compile-time. The is nothing dynamic or virtual about it. So if you have:
public T SomeMethod<T>() where T : SomeBaseClass
{
T rv = ...;
if (rv != null)
{
then which overload of != to use will be fixed, at compile-time, with usual overload resolution (including a few special rules for ==). The rv has type T which is known to be a reference type eqaul to or deriving from SomeBaseClass. So the best overload is chosen based on that. That might be the operator !=(object, object) overload (built-in) if SomeBaseClass does not define (or "inherit") an appropriate overload.
At run-time, then, even if the actual substitution for T happens to be a more specific type SomeEqualityOverloadingClass (that satisfies the constraint of course), that does not mean a new overload resolution will happen at run-time!
This is different from the virtual method .Equals(object).
In C#, generics do not work like templates, and they are not like dynamic.
If you really want dynamic overload resolution (binding at run-time instead of at compile-time), it is allowed to say if ((dynamic)rv != null).

Serializing null in JSON.NET

When serializing arbitrary data via JSON.NET, any property that is null is written to the JSON as
"propertyName" : null
This is correct, of course.
However I have a requirement to automatically translate all nulls into the default empty value, e.g. null strings should become String.Empty, null int?s should become 0, null bool?s should be false, and so on.
NullValueHandling is not helpful, since I dont want to Ignore nulls, but neither do I want to Include them (Hmm, new feature?).
So I turned to implementing a custom JsonConverter.
While the implementation itself was a breeze, unfortunately this still didnt work - CanConvert() is never called for a property that has a null value, and therefore WriteJson() is not called either. Apparently nulls are automatically serialized directly into null, without the custom pipeline.
For example, here is a sample of a custom converter for null strings:
public class StringConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(string).IsAssignableFrom(objectType);
}
...
public override void WriteJson(JsonWriter writer,
object value,
JsonSerializer serializer)
{
string strValue = value as string;
if (strValue == null)
{
writer.WriteValue(String.Empty);
}
else
{
writer.WriteValue(strValue);
}
}
}
Stepping through this in the debugger, I noted that neither of these methods are called for properties that have a null value.
Delving into JSON.NET's sourcecode, I found that (apparently, I didnt go into a lot of depth) there is a special case checking for nulls, and explictly calling .WriteNull().
For what it's worth, I did try implementing a custom JsonTextWriter and overriding the default .WriteNull() implementation...
public class NullJsonWriter : JsonTextWriter
{
...
public override void WriteNull()
{
this.WriteValue(String.Empty);
}
}
However, this can't work well, since the WriteNull() method knows nothing about the underlying datatype. So sure, I can output "" for any null, but that doesnt work well for e.g. int, bool, etc.
So, my question - short of converting the entire data structure manually, is there any solution or workaround for this?
Okay, I think I've come up with a solution (my first solution wasn't right at all, but then again I was on the train). You need to create a special contract resolver and a custom ValueProvider for Nullable types. Consider this:
public class NullableValueProvider : IValueProvider
{
private readonly object _defaultValue;
private readonly IValueProvider _underlyingValueProvider;
public NullableValueProvider(MemberInfo memberInfo, Type underlyingType)
{
_underlyingValueProvider = new DynamicValueProvider(memberInfo);
_defaultValue = Activator.CreateInstance(underlyingType);
}
public void SetValue(object target, object value)
{
_underlyingValueProvider.SetValue(target, value);
}
public object GetValue(object target)
{
return _underlyingValueProvider.GetValue(target) ?? _defaultValue;
}
}
public class SpecialContractResolver : DefaultContractResolver
{
protected override IValueProvider CreateMemberValueProvider(MemberInfo member)
{
if(member.MemberType == MemberTypes.Property)
{
var pi = (PropertyInfo) member;
if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof (Nullable<>))
{
return new NullableValueProvider(member, pi.PropertyType.GetGenericArguments().First());
}
}
else if(member.MemberType == MemberTypes.Field)
{
var fi = (FieldInfo) member;
if(fi.FieldType.IsGenericType && fi.FieldType.GetGenericTypeDefinition() == typeof(Nullable<>))
return new NullableValueProvider(member, fi.FieldType.GetGenericArguments().First());
}
return base.CreateMemberValueProvider(member);
}
}
Then I tested it using:
class Foo
{
public int? Int { get; set; }
public bool? Boolean { get; set; }
public int? IntField;
}
And the following case:
[TestFixture]
public class Tests
{
[Test]
public void Test()
{
var foo = new Foo();
var settings = new JsonSerializerSettings { ContractResolver = new SpecialContractResolver() };
Assert.AreEqual(
JsonConvert.SerializeObject(foo, Formatting.None, settings),
"{\"IntField\":0,\"Int\":0,\"Boolean\":false}");
}
}
Hopefully this helps a bit...
Edit – Better identification of the a Nullable<> type
Edit – Added support for fields as well as properties, also piggy-backing on top of the normal DynamicValueProvider to do most of the work, with updated test

Telling HashSet to use IEquatable?

What I've read on the HashSet is it uses the default comparer for a class. I'm expecting the code below to fail when adding the second Spork to the hash set. I think my understanding of what is happening is incomplete. From MSDN of the HashSet constructor:
The IEqualityComparer implementation to use when comparing values in the set, or null to use the default EqualityComparer implementation for the set type.
So what is the default comparer, and how can I tell .Net to use my own comparer?
public class Spork : IEquatable<Spork>
{
public int Id { get; set; }
public bool Equals(Spork other)
{
return other != null && other.Id == this.Id;
}
public override bool Equals(object obj)
{
var other = obj as Spork;
return other != null && other.Id == this.Id;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
public class Bjork
{
public static HashSet<Spork> Sporks { get; set; }
public static void Main()
{
Sporks = new HashSet<Spork>();
Sporks.Add(new Spork() { Id = 0 });
Sporks.Add(new Spork() { Id = 0 }); // come on, please throw an exception
}
}
It is using your equality methods - but HashSet<T>.Add doesn't throw an exception when you try to add an equal value - it just returns false.
If you change the last two lines to print out the return value of Add, you'll see it returns True the first time, then False.
If your goal is to work like the Dictionary and disallow the same entry multiple times and throw an exception, you would have to inherit from HashSet and IEquatable:
class UniqueHashSet<T> : HashSet<T>, IEquatable<T>
Then, of course, write a new .Add() method to hide the base Add.
But, I'm sure there is a better way.
Or, as #Jon says, it does maintain a unique collection.

checking two object instances to see if they are the same

i need to compare two objects but compare a number of their properties in one hit.
this is not for sorting, but instead to confirm whether anything has changed; as one is the old saved instance, and the second is a newly imported instance of the same thing
i assume this is best served by writing a custom comparer. just am a bit confused as to whether to do IComparer, or IComparable, or what tbh.
thanks
nat
If you only have a single definition of equality for your class, you don't really need to implement any interface: simply override the Equalsmethod. Best practice though, would be to implement IEquatable<T>and to override GetHashCode sensibly (if you don't override the hash-code, equality will misbehave when collection classes, LINQ methods etc. use it as a pre-condition for equality). Here's a sample implementation:
public class Person : IEquatable<Person>
{
public string Name { get; set; }
public int Age { get; set; }
public override int GetHashCode()
{
return (Name == null ? 0 : Name.GetHashCode()) ^ Age;
}
public override bool Equals(object obj)
{
return Equals(obj as Person);
}
public bool Equals(Person other)
{
return other != null && other.Name == Name && other.Age == Age;
}
}
This will allow you to do:
Person savedPerson = ...
Person importedPerson = ...
bool hasChanged = !savedPerson.Equals(importedPerson);
If, on the other hand, you do have lots of different definitions of equality for different circumstances, your best bet would be to write up different IEqualityComparer<T>implementations. Here's a sample implementation:
public class AgeComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
return (x == null || y == null) ? x == y : x.Age == y.Age;
}
public int GetHashCode(Person obj)
{
return obj == null ? 0 : obj.Age;
}
}
In this case, the check will look like:
Person savedPerson = ...
Person importedPerson = ...
IEqualityComparer<Person> comparer = ...
bool hasChanged = !comparer.Equals(savedPerson, importedPerson);
As you have alluded to IComparable is typically used for sorting.
In this case you would want to overload the comparison operator: ==
Because the reverse comparison should also be valid, this implies you must also overload the != operator.
When you overload == and !- you are also expected to override Equals and GetHashCode.
A decent C# book should explain the details.
An alternative to implementing the IComparable interface would be to override the Equals and GetHashCode functions.
That is about how you want to perform compare operation. You can do the operation in both ways:
public void Method()
{
Foo p1 = new Foo();
Foo p2 = new Foo();
p1.CompareTo(p2);
FooComparer c = new FooComparer();
c.Compare(p1, p2);
}
class Foo : IComparable
{
public int CompareTo(object obj)
{
throw new NotImplementedException();
}
}
class FooComparer : IComparer<Foo>
{
public int Compare(Foo x, Foo y)
{
throw new NotImplementedException();
}
}
I prefer using IComparer as seperation of concerns. Foo is my class, I have some busines needs on it. If I want to compare some Foos, I use FooComparer. For your situation you can return the number of changed properties from Compare method. If Compare method return 0. Then two Foos are same.
As I said. That is completely how you want to perform the action I think. Overriding Equality Operators are also good solution. Implementing IEqualityComparer<T> is another solution.
Yes you will need your type to implement IComparable. Here is a sample on how to do it.

Categories