1

On C# I'm having this issue as presented it the image. Does anyone knows why the Equals implementation is not giving me the expected behaviour? Wasn't supposed to return true because the value is the same?

IFormattable Equals

  • 6
    I think you want to call `.ToString()` and use `.Equals`, else it may be that it is comparing their references for equality. – Ryan Wilson Jan 15 '19 at 14:06
  • 1
    Try `((IFormattable) ($"string1")).GetType()`. The type the compiler uses to implement formattable strings does not override `.Equals` (nor is it required to). Indeed, it's not clear if such a comparison would be useful -- the actual value of a formattable string will differ depending on the runtime values used in the expression, so it's not normally useful to know that two formatting strings are the same (as opposed to the strings after formatting). (But if you really needed it, you could go through `FormattableString.Format`.) – Jeroen Mostert Jan 15 '19 at 14:10
  • It will most probably create object of base class `FormattableString`. And these classes doesn't override Equals method. https://referencesource.microsoft.com/#mscorlib/system/FormattableString.cs,52d4a4f6c1013607 – fhnaseer Jan 15 '19 at 14:18
  • 1
    If like me you were surprised that a string literal didn't produce a string object then https://stackoverflow.com/questions/35425899/difference-between-string-formattablestring-iformattable discusses it a bit more. – Chris Jan 15 '19 at 14:30
  • Those are two different instances. [IFormattable](https://learn.microsoft.com/en-us/dotnet/api/system.iformattable?view=netframework-4.7.2) itself only defines a `ToString()` method. It's not possible to say if two instances that implement that interface are equal or not. Both `DateTime` and `Double` implement `IFormattable` – Panagiotis Kanavos Jan 15 '19 at 14:31
  • @RyanWilson That example is simple without string interpolation, but my goal of using IFormattable is to postpone the creation of strings only when needed. I went to visual studio and saw that x instance type is System.Runtime.CompilerServices.FormattableStringFactory+ConcreteFormattableString and that in fact does not implement Equals. – Vitor Paulino Jan 15 '19 at 17:00
  • @VitorPaulino All class types have a base of `Object` so even if they don't define (override) `.Equals` the base class `Object.Equals` is available to be used. – Ryan Wilson Jan 15 '19 at 17:19
  • The question was if anyone knows why the Equals is not implemented. Im well aware of .NET and C# language. the ToEquals method that is called no matter the type should allways compare for value equality. I was expecting that the ToEquals would me smarter over the concreteFormattableString. Because if there are no arguments it could execute the ToEquals of a string. – Vitor Paulino Jan 16 '19 at 18:22
  • Here is the source code: https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/runtime/compilerservices/FormattableStringFactory.cs – Vitor Paulino Jan 16 '19 at 18:22

2 Answers2

3

Since FormattableString doesn't override .Equals and neither does ConcreteFormattableString which inherits from FormattableString, it reverts to Object.Equals which compares references for equality, that is why your current code returns false. A quick fix would be to call .ToString() on both objects and use the string.Equals override as it compares the value of each string.

So you could switch your last line to this and it should produce true:

Console.WriteLine(string.Equals(x.ToString(), u.ToString()));

Documentation:

string.Equals(): https://learn.microsoft.com/en-us/dotnet/api/system.string.equals?view=netframework-4.7.2

FormattableString: https://learn.microsoft.com/en-us/dotnet/api/system.formattablestring?view=netframework-4.7.2

ConcreteFormattableString: https://weblogs.asp.net/dixin/csharp-6-0-string-interpolation-formattablestring-and-code-analysis-ca1305-specify-iformatprovider

Ryan Wilson
  • 10,223
  • 2
  • 21
  • 40
2

The type of your variables are ConcreteFormattableString because of this assignment:

IFormattable x = $"string1"; // ConcreteFormattableString
var x = $"string1"; // this is regular string

And ConcreteFormattableString doesn't override Equals method, so object.Equals method is called which compares references. Since the two string have different references, you get false.

As mentioned in the comments if you want to compare contents of the strings, you can call ToString, then perform the comparison.

Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • 1
    Technically it's not `IFormattable` at all since that's just an interface. It's the underlying class `ConcreteFormattableString` that doesn't override `Equals`. – juharr Jan 15 '19 at 14:11
  • @juharr I wasn't aware that `IFormattable x = $"string1";` creates a different type of string. Updated my answer. – Selman Genç Jan 15 '19 at 14:34