1

im learning c# and i cant underestand that why are the results different in the following code:

public class Thing
{
    public object Data = default(object);
    public string Process(object input)
    {
        if (Data == input)
        {
            return "Data and input are the same.";
        }
        else
        {
            return "Data and input are NOT the same.";
        }
    }
}

and inside main method:

var t1 = new Thing();
t1.Data = 42;
Console.WriteLine($"Thing with an integer: {t1.Process(42)}");
var t2 = new Thing();
t2.Data = "apple";
Console.WriteLine($"Thing with a string: {t2.Process("apple")}");

and the output is:

Thing with an integer: Data and input are NOT the same.
Thing with a string: Data and input are the same.

2 Answers2

1

The root of this behaviour is boxing. This is when assigning a .net value type, like an integer, to an object reference requires the creation of an object to hold the value. Because you do this twice - firstly when assigning 42 to Data and then by passing 42 as an object parameter, they are boxed into different objects which obey reference equality.

Strings are already objects but they are a special type in .net which overrides equality - see the rules.

Tom W
  • 5,108
  • 4
  • 30
  • 52
0

See discussion which contains answer by @AFract!

He basically says that if (Data == input) has to be replaced by if (Data.Equals(input)) then the problem is solved. Please upvote his comment!

I tried this to test input type:

using System;

public class Thing
{
    public object Data = default(object);
    
    public string Process(object input)
    {
        if (Data.Equals(input))
        {
            return "Data and input are the same.";
        }
        else
        {
            return "Data and input are NOT the same.";
        }
    }
    
    public dynamic Input(object myinput)
    {
      return myinput;   
    }
}

public class Program
{
    public static void Main()
    {
        var t1 = new Thing();
        t1.Data = 42;
        Console.WriteLine($"Thing with an integer: {t1.Process(42)}");
        var t2 = new Thing();
        t2.Data = "apple";
        Console.WriteLine($"Thing with a string: {t2.Process("apple")}");
        Console.WriteLine($"{t1.Input(42).GetType()}");
    }
}

Output is:

Thing with an integer: Data and input are the same.
Thing with a string: Data and input are the same.
System.Int32
Gwang-Jin Kim
  • 9,303
  • 17
  • 30
  • This is a good answer but it could even be better by showing how to convert it! – aybe Apr 25 '21 at 07:38
  • 1
    He compares "apple" with "apple", and 42 with 42. He wants to know why "apple" is not equal to "apple", so no, this answer doesn't provide anything useful. – AFract Apr 25 '21 at 07:41
  • @aybe I am myself quite new to C# - so do you know how to convert it automatically/dynamically? – Gwang-Jin Kim Apr 25 '21 at 07:41
  • @AFract - "apple" with "apple" gave that it is equal. He was asking why 42 with 42 came to result that they are not equal - and I showed why. – Gwang-Jin Kim Apr 25 '21 at 07:42
  • @AFract I also thought at beginning that it must be other way round. I thought it might have to do with object identity etc. - but when I tried in C# I realized 42 makes the problem - it is because he forgot to cast input (which is string) into a number. – Gwang-Jin Kim Apr 25 '21 at 07:45
  • 1
    Question has been closed ... still, any object in C# has `ToString` method. For the other way around there is the `System.Convert` class that will convert `IConvertible` types, numbers all do implement this interface. – aybe Apr 25 '21 at 07:47
  • @Gwang-JinKim I don't understand what you mean, he compares same types and same values (but not references) in its question. If you replace "Data == input" (which is internally translated by Object.ReferenceEquals in c#) by for example "Data.Equals(input)" his problem will be fixed. For me THIS is the right information to give, and it has nothing to do with different types comparison (like comparing "42" (string) with 42 (int)), etc.The important point here is Reference comparison, vs value types. – AFract Apr 25 '21 at 07:50
  • @AFract Thank you - you are right! with `Data.Equals(input)` the problem is solved! Thanks! – Gwang-Jin Kim Apr 25 '21 at 07:52
  • sorry but i dont think that you are answering my question. the input type in t1.process(42) is int and the t1.data type is int too. so inside process method it is comparing two integers(input=42 and data=42). but the = operator is being bind to object type's = operator. i cant underestand why the same code for string "apple" has different result. i know it is related to refrence type and value type but i dont know how exactlly – mohammad soghrati Apr 25 '21 at 07:53
  • @mohammadsoghrati The correct answer is from @AFract: replace `if (Data == input)` by `if (Data.Equals(input))` and then the code works. – Gwang-Jin Kim Apr 25 '21 at 07:54
  • @mohammadsoghrati How you know the types are both int? I showed you that one can see the type by `.GetType()`. - input is string. - In Python it is the same. And in Python, usually one has to do `int(input)` when input should be integer. – Gwang-Jin Kim Apr 25 '21 at 07:56
  • 1
    @mohammadsoghrati unfortunately I think your question have been closed a little too soon to allow you to receive a detailed answer. But you'll find it on other questions like yours and I hope you will understand at the end. Here's a short explanation : when you create "apple" twice stored in "object" variables, you create two different "apple" objects, in different memory locations. So comparing them as objects will tell you they're not the same. But you can force c# to compare more smartly, by using the Equals method (or IConvertible type). Instead of objects they'll be processed as string – AFract Apr 25 '21 at 07:58
  • 1
    ... Because "==" is redefined for strings, doing string == string does not behave as object == object. In first case C# will compare the content of those strings, in second it will just compare the memory locations of both objects. – AFract Apr 25 '21 at 08:00
  • 1
    @mohammadsoghrati @AFract and you are right. I now realize that `t1.Process(42)` returns your answer string - that is why it is a string - and it is not because the input is a string I guess. Sorry to all. – Gwang-Jin Kim Apr 25 '21 at 08:01
  • @Gwang-JinKim no problem, we're all here to help and to learn :) – AFract Apr 25 '21 at 08:01
  • 1
    I tried now as shown - the input type is correctly Integer. So my original answer was wrong. C# behaves differently in terms of input from Python ;) . – Gwang-Jin Kim Apr 25 '21 at 08:07