Comparing 2 reference strings returns true [duplicate] - c#

This question already has answers here:
Intern string literals misunderstanding?
(2 answers)
Closed 6 years ago.
string a = "abc";
string b = "abc";
Console.WriteLine(String.ReferenceEquals(a, b));
a and b are CLEARLY different references, yet, I get true. Why is this? Somewhere I've read that when you assign abc to b, the compiler sees that there's already the exact abc value in the heap and points to the same memory address as a, but if this was the case, then by that logic the last line of this code below should print true:
class SomeClass
{
public int _num;
public SomeClass(int num)
{
_num = num;
}
}
var a = new SomeClass(3);
var b = new SomeClass(3);
Console.WriteLine(Object.ReferenceEquals(a, b)); // prints false

a and b are CLEARLY different references.
No, they are not. That string is interned.
The 'catch' with strings in general is that == calls the string.Equals method, which does not only compare references, but also the actual representation of the string.
Proof:
string a = "a";
string b = "a"; // intering
string c = new string(a.ToCharArray()); // no interning
bool r;
r = a == b; // true: references the same
r = a == c; // true: references different, match string value
r = (object)a == (object)b; // true: references the same
r = (object)a == (object)c; // false: references different

In the compilation step, string literals are pooled and all references to a specific value will be equal.
From the specifications (boldface mine):
Each string literal does not necessarily result in a new string instance. When two or more string literals that are equivalent according to the string equality operator (Section 7.9.7) appear in the same assembly, these string literals refer to the same string instance.

Related

Unexpected inequality for list elements when passed into a function (but not locally) [duplicate]

This question already has answers here:
Difference between == operator and Equals() method in C#?
(3 answers)
Closed 2 years ago.
I am trying to implement a function that compares elements of different lists. I keep getting unexpected behavior, where apparently OpCodes.Brfalse != OpCodes.Brfalse or 12 != 12.
It only seems to exhibit this behavior when I pass lists of items as parameters to a function that compares their individual elements, not when I compare them locally.
[TestMethod()]
public void findListMatch_TEST()
{
var alist = new List<Harmony.CodeInstruction>()
{
new Harmony.CodeInstruction(OpCodes.Brfalse, 12),
};
var blist = new List<Harmony.CodeInstruction>()
{
new Harmony.CodeInstruction(OpCodes.Brfalse, 12),
};
Assert.AreEqual(alist[0].opcode, blist[0].opcode); //Passes
Assert.AreEqual(alist[0].operand, blist[0].operand); //Passes
Assert.IsTrue(Foo(alist, blist)); //Fails
}
bool Foo(List<Harmony.CodeInstruction> alist, List<Harmony.CodeInstruction> blist)
{
var A = alist[0];
var B = blist[0];
if (A.opcode != B.opcode)
{
return false; //Hit this sometimes, expect not to
}
else if (A.operand != B.operand)
{
return false; //Hit this sometimes, expect not to
}
return true;
}
Harmony.CodeInstruction is a class with fields opcode {System.Reflection.Emit.OpCode} and operand {object} from the Harmony library.
in CodeInstruction class source code operand field is of type object.
So your first comparison checks for equality using Object.Equals method
// Uses Object.Equals
Assert.AreEqual(alist[0].operand, blist[0].operand);
Your second comparison is reference equals which will be false.
// Reference comparison will be false because both are boxing value 12 in different memory locations.
A.operand != B.operand
You can easily test this in a simple console application
object a = 12;
object b = 12;
Console.WriteLine(a.Equals(b)); // True
Console.WriteLine(a == b); // False

Input string was not in a correct format. Textchange problem [duplicate]

This question already has answers here:
Input string was not in a correct format
(9 answers)
Closed 3 years ago.
C# CODE
I have a problem with my "Check in" form.
I want to multiply the txtsubtotal and txtadvancepayment.
In textchange if I put number on the txtadvancepayment, the overallresult is correct. But if I clear the txtadvancepayment (Incase when the user puts a wrong value) it would be error. The error says "Input string was not in a correct format."
What should I do?
My Code downward
int overalltotal = 0;
int a = Convert.ToInt32(txtsubtotal.Text);
int b = Convert.ToInt32(txtadvancepayment.Text);
overalltotal = a - b;
txttotalbalance.Text = overalltotal.ToString();
An empty string cannot be parsed as an int. As others have mentioned, you can use int.TryParse which accepts a string as the first parameter and an out int as the second parameter, which holds the parsed value. You could do this:
int overallTotal = 0;
int a = 0;
int b = 0;
// TryParse returns a bool
// If either of these fails, the variable a or b will keep the default 0 value
int.TryParse(txtSubtotal.Text, out a);
int.TryParse(txtAdvancePayment.Text, out b);
// Sum a and b
overallTotal = a + b;
If you want to show an error to the user that one or both fields isn't a valid integer, you can assign a bool variable such as var aIsNumber = int.TryParse(...) and then check if aIsNumber or bIsNumber is false. If so, then a and/or b could not be parsed to an int.
You could use Int32.TryParse.
Int32.Parse attempts to convert the string representation of a number to its 32-bit signed integer equivalent and returns value indicates whether the operation succeeded. This would mean, in case your textbox is empty or contains a invalid numeric representation, and the method would return false since it would not be able to convert it to int32
For example
if(Int32.TryParse(txtsubtotal.Text,out var a)
&& Int32.TryParse(txtadvancepayment.Text,out var b))
{
// Code which requires a and b
}

string interning and referenceEquals

I'm trying to understand string interning. Not for any real purpose other than learning.
Here's where I'm at:
Strings are immutable and a reference type. Its this immutability that allows us to do string interning.
Without string interning, the two strings will be two strings on the heap.
e.g.
private static void Main()
{
var a = "foo";
var b = "foo";
ReferenceEquals(a, b); // would expect this to be false...
}
I would expect that ReferenceEquals to be false. It isn't though it's true. I thought to make it true I would have to do:
private static void Main()
{
var a = "foo";
var b = "foo";
ReferenceEquals(a, b); // false??
string.Intern(a);
string.Intern(b);
ReferenceEquals(a, b); // true?
}
Since the interning process, as I understand it, looks for the string in a hash table and if its not there it adds it. On further interning it looks for the string and if it finds it, then it changes the reference to point to the same place in the hash table.
This should speed up comparisons? Since it it doesn't need to check if each char matches and can just check if both strings point to the same location. (Let's ignore the overhead of actually interning for now till I understand how this works).
So what am I not getting. Why is the first code block returning true and not false?
This occurs because "foo" is interned.
static void Main(string[] args)
{
var a = "foo";
var b = "foo";
Console.WriteLine(string.IsInterned(a));
Console.WriteLine(ReferenceEquals(a, b));
Console.ReadLine();
}
The compiler will intern all literals / constants by default.

Comparing values using == operator

I have a static method which simply compares two values and returns the result
public class Calculator
{
public static bool AreEqual(object value1, object value2)
{
return value1 == value2;
}
}
bool Equal = Calculator.AreEqual("a", "a"); // returns true
bool Equal = Calculator.AreEqual(1, 1); // returns false
Can someone please explain what is going on behind the scenes that produces the output described above
The runtime identifies your literal usages of "a" and retrieves the same reference to all those usages, resulting in one string object rather than two as you would expect.
Instead of using literals, try the following:
string A1 = new string(new char[] {'a'});
string A2 = new string(new char[] {'a'});
Calculator.AreEqual(A1, A2); // returns false
What you've presented here is known as string interning.
You can find more information in the String.Intern method page.

c# check if 2 string includes the same chars

I created 3 strings:
string a = "abcdgfg";
string b = "agbfcd";
string c = "axcvn";
I want to create the following check but i can't find out how:
Need to check if in string a and string b there are the same latters (never mind the order or if a latter shown more than once, just need to check if the same latter appears on both strings).
Then i need to do the same check for string a and string c.
as you can see: string a and string b have the same latters, stringa a and string c don't.
after i do the checking i simply print a massage if the strings have the same latter or not
Can anyone show me how to do the cheking?
Edit:
after check "a" and "c", it o should print the first latter that came up and not match between "a" and "c"
Thanks
I would suggest to use a HashSet<T> and it's SetEquals:
var aSet = new HashSet<char>(a);
var bSet = new HashSet<char>(b);
bool abSame = aSet.SetEquals(b);
Edit
after check "a" and "c", it o should print the first latter that came
up and not match between "a" and "c"
Then you can use HashSet.SymmetricExceptWith:
if (!abSame)
{
aSet.SymmetricExceptWith(bSet);
Console.WriteLine("First letter that is either in a and not in b or in b and not in a: " + aSet.First());
}
By the way, this can also replace the SetEquals check:
aSet.SymmetricExceptWith(bSet); // removes all characters which are in both
if (aSet.Any()) // missing charaters in one of both strings
{
Console.WriteLine("First letter that is either in a and not in b or in b and not in a: " + aSet.First());
}
The original answer using Except + Any had a subtle bug. Checking the length is not sufficient if there are duplicates. So you need to check from both directions or use Distinct first. Both approaches are inefficient compared to the HashSet.SetEquals-method which is a O(n) operation.
bool abSame = !a.Except(b).Any() && !b.Except(a).Any();
private bool HaveSameLetters(string a, string b)
{
return a.All(x => b.Contains(x)) && b.All(x => a.Contains(x));
}
Need to check if in string a and string b there are the same latters (never mind the order or if a latter shown more than once, just need to check if the same latter appears on both strings).
You can do it like this:
bool same = a.Distinct().OrderBy(c => c)
.SequenceEqual(b.Distinct().OrderBy(c => c));
This simply sorts the characters of two strings and checks if the two ordered sequence are equal. You can use the same method for a and c.

Categories