Simple if between two strings fails [duplicate] - c#

I have the following C# code (from a library I'm using) that tries to find a certificate comparing the thumbprint. Notice that in the following code both mycert.Thumbprint and certificateThumbprint are strings.
var certificateThumbprint = AppSettings.CertificateThumbprint;
var cert =
myStore.Certificates.OfType<X509Certificate2>().FirstOrDefault(
mycert =>
mycert.Thumbprint != null && mycert.Thumbprint.Equals(certificateThumbprint)
);
This fails to find the certificate with the thumbprint because mycert.Thumbprint.Equals(certificateThumbprint) is false even when the strings are equal. mycert.Thumbprint == certificateThumbprint also returns false, while mycert.Thumbprint.CompareTo(certificateThumbprint) returns 0.
I might be missing something obvious, but I can't figure out why the Equals method is failing. Ideas?

CompareTo ignores certain characters:
static void Main(string[] args)
{
var a = "asdas"+(char)847;//add a hidden character
var b = "asdas";
Console.WriteLine(a.Equals(b)); //false
Console.WriteLine(a.CompareTo(b)); //0
Console.WriteLine(a.Length); //6
Console.WriteLine(b.Length); //5
//watch window shows both a and b as "asdas"
}
(Here, the character added to a is U+034F, Combining Grapheme Joiner.)
So CompareTo's result is not a good indicator of a bug in Equals. The most likely reason of your problem is hidden characters. You can check the lengths to be sure.
See this for more info.

You may wish to try using an overload of String.Equals that accepts a parameter of type StringComparison.
For example:
myCert.Thumbprint.Equals(certificateThumbprint, StringComparison.[SomeEnumeration])
Where [SomeEnumeration] is replaced with one of the following enumerated constants:
- CurrentCulture
- CurrentCultureIgnoreCase
- InvariantCulture
- InvariantCultureIgnoreCase
- Ordinal
- OrdinalIgnoreCase
Reference the MSDN Documentation found here.

Sometimes when we insert data in database it stores some spaces like "question ". And when you will try to compare it with "question" it returns false. So my suggestion is: please check the value in database or use Trim() method.
In your case, please try:
mycert.Thumbprint != null && mycert.Thumbprint.trim().equals(certificateThumbprint.trim())
I think it will return true if any record will exist.

Related

AND operation in C#

I want to perform an AND operation. My inputs are 2 objects. It could be a string like "true" or it could be an expression like "1==1" as well. When using && operator, am getting an exception that String was not recognized as a valid boolean.
Please help me.
return Convert.ToBoolean(obj[0]) && Convert.ToBoolean(obj[1]);
Sorry for the earlier post which was not clear enough.
Converting "1==1" to a boolean is not possible for the Convert.ToBoolean method. It just converts the strings true and false.
You will have to either write a expression evaluator yourself, or use some kind of library to parse your string to a boolean (like Flee for example)
First make sure obj[0], obj[1] will only contain 1 or 0(char or integer).
Because Convert.ToBoolean does not understand anything other than 1 or 0.
The below one will work
Convert.ToBoolean(true) && Convert.ToBoolean(1==1)
Why use a string?
The conversion will not evaluate code, it will check if the supplied data is possible to convert to a bool and do so if possible.
Your function will always return true if it was working, cause 1 is always equal to 1, and true is always true.
This is nearly impossible as C# is strongly type language.
What you trying to do is for weakly types languages like JS. "1==1" will work for JS, not for C#.
Remove quotes in order to make it work(You might as well remove first operand, as it doesn't make any sense):
return ( 1 == 1 );

Bug in the string comparing of the .NET Framework

It's a requirement for any comparison sort to work that the underlying order operator is transitive and antisymmetric.
In .NET, that's not true for some strings:
static void CompareBug()
{
string x = "\u002D\u30A2"; // or just "-ア" if charset allows
string y = "\u3042"; // or just "あ" if charset allows
Console.WriteLine(x.CompareTo(y)); // positive one
Console.WriteLine(y.CompareTo(x)); // positive one
Console.WriteLine(StringComparer.InvariantCulture.Compare(x, y)); // positive one
Console.WriteLine(StringComparer.InvariantCulture.Compare(y, x)); // positive one
var ja = StringComparer.Create(new CultureInfo("ja-JP", false), false);
Console.WriteLine(ja.Compare(x, y)); // positive one
Console.WriteLine(ja.Compare(y, x)); // positive one
}
You see that x is strictly greater than y, and y is strictly greater than x.
Because x.CompareTo(x) and so on all give zero (0), it is clear that this is not an order. Not surprisingly, I get unpredictable results when I Sort arrays or lists containing strings like x and y. Though I haven't tested this, I'm sure SortedDictionary<string, WhatEver> will have problems keeping itself in sorted order and/or locating items if strings like x and y are used for keys.
Is this bug well-known? What versions of the framework are affected (I'm trying this with .NET 4.0)?
EDIT:
Here's an example where the sign is negative either way:
x = "\u4E00\u30A0"; // equiv: "一゠"
y = "\u4E00\u002D\u0041"; // equiv: "一-A"
If correct sorting is so important in your problem, just use ordinal string comparison instead of culture-sensitive. Only this one guarantees transitive and antisymmetric comparing you want.
What MSDN says:
Specifying the StringComparison.Ordinal or
StringComparison.OrdinalIgnoreCase value in a method call signifies a
non-linguistic comparison in which the features of natural languages
are ignored. Methods that are invoked with these StringComparison
values base string operation decisions on simple byte comparisons
instead of casing or equivalence tables that are parameterized by
culture. In most cases, this approach best fits the intended
interpretation of strings while making code faster and more reliable.
And it works as expected:
Console.WriteLine(String.Compare(x, y, StringComparison.Ordinal)); // -12309
Console.WriteLine(String.Compare(y, x, StringComparison.Ordinal)); // 12309
Yes, it doesn't explain why culture-sensitive comparison gives inconsistent results. Well, strange culture — strange result.
I came across this SO post, while I was trying to figure out why I was having problems retrieving (string) keys that were inserted into a SortedList, after I discovered the cause was the odd behaviour of the .Net 40 and above comparers (a1 < a2 and a2 < a3, but a1 > a3).
My struggle to figure out what was going on can be found here: c# SortedList<string, TValue>.ContainsKey for successfully added key returns false.
You may want to have a look at the "UPDATE 3" section of my SO question. It appears that the issue was reported to Microsoft in Dec 2012, and closed before the end of january 2013 as "won't be fixed". Additionally it lists a workaround that may be used.
I created an implementation of this recommended workaround, and verified that it fixed the problem that I had encountered. I also just verified that this resolves the issue you reported.
public static void SO_13254153_Question()
{
string x = "\u002D\u30A2"; // or just "-ア" if charset allows
string y = "\u3042"; // or just "あ" if charset allows
var invariantComparer = new WorkAroundStringComparer();
var japaneseComparer = new WorkAroundStringComparer(new System.Globalization.CultureInfo("ja-JP", false));
Console.WriteLine(x.CompareTo(y)); // positive one
Console.WriteLine(y.CompareTo(x)); // positive one
Console.WriteLine(invariantComparer.Compare(x, y)); // negative one
Console.WriteLine(invariantComparer.Compare(y, x)); // positive one
Console.WriteLine(japaneseComparer.Compare(x, y)); // negative one
Console.WriteLine(japaneseComparer.Compare(y, x)); // positive one
}
The remaining problem is that this workaround is so slow it is hardly practical for use with large collections of strings. So I hope Microsoft will reconsider closing this issue or that someone knows of a better workaround.

string.Compare("KHA","KTB",true) return incorrect result in C#

I am using C#, .NET 3.5. I have following code
string.Compare("KHA","KTB",true)
It returned value 1. This means KHA > KTB in alphabet order.
I expect it returns value -1.
Can anyone help me fix this?
Yes, all of you are right. It's because of the Culture. I add CultureInfo.InvariantCulture and it is solved.
Thanks all!
strig.Compare returns the relative position in the sort order. Since 'H' comes before 'T' that is why you are getting 1
Its should return -1, See the image
There must be something wrong going on with your compiler, it should return -1 and your understanding for the string.Compare is right.
You may try using CultureInfo.InvariantCulture:
int value = string.Compare("KHA", "KTB", true,CultureInfo.InvariantCulture);
The call string.Compare("KHA","KTB",true) should return -1 as expected. It does when I test it.
If you get any other result, you either are using other strings, or you have a default culture where 'T' is actually considered to come before 'H'.
For the latter case, you can specify a culture info in the call:
string.Compare("KHA", "KHB", true, CultureInfo.InvariantCulture)
If you are really getting 1 against string.Compare("KHA","KTB",true) then your system's current culture must be making an effect. Check the documentation of String.Compare. Also check the best practices of comparing a string here.

Why does Enumerable.All return true for an empty sequence? [duplicate]

This question already has answers here:
Why does IQueryable.All() return true on an empty collection?
(11 answers)
Closed 7 years ago.
var strs = new Collection<string>();
bool b = strs.All(str => str == "ABC");
The code creates an empty collection of string, then tries to determine if all the elements in the collection are "ABC".
If you run it, b will be true.
But the collection does not even have any elements in it, let alone any elements that equal to "ABC".
Is this a bug, or is there a reasonable explanation?
It's certainly not a bug. It's behaving exactly as documented:
true if every element of the source sequence passes the test in the specified predicate, or if the sequence is empty; otherwise, false.
Now you can argue about whether or not it should work that way (it seems fine to me; every element of the sequence conforms to the predicate) but the very first thing to check before you ask whether something is a bug, is the documentation. (It's the first thing to check as soon as a method behaves in a way other than what you expected.)
All requires the predicate to be true for all elements of the sequence. This is explicitly stated in the documentation. It's also the only thing that makes sense if you think of All as being like a logical "and" between the predicate's results for each element. The true you're getting out for the empty sequence is the identity element of the "and" operation. Likewise, the false you get from Any for the empty sequence is the identity for logical "or".
If you think of All as "there are no elements in the sequence that are not", this might make more sense.
It is true, as nothing (no condition) makes it false.
The docs probably explain it. (Jon Skeet also mentioned something a few years back)
Same goes for Any (the opposite of All) returning false for empty sets.
Edit:
You can imagine All to be implemented semantically the same as:
foreach (var e in elems)
{
if (!cond(e))
return false;
}
return true; // no escape from loop
Most answers here seem to go along the lines of "because that's how is defined". But there is also a logical reason why is defined this way.
When defining a function, you want your function to be as general as possible, such that it can be applied to the largest possible number of cases. Say, for instance, that I want to define the Sum function, which returns the sum of all the numbers in a list. What should it return when the list is empty? If you'd return an arbitrary number x, you'd define the function as the:
Function that returns the sum of all numbers in the given list, or x if the list is empty.
But if x is zero, you can also define it as the
Function that returns x plus the given numbers.
Note that definition 2 implies definition 1, but 1 does not imply 2 when x is not zero, which by itself is enough reason to pick 2 over 1. But also note 2 is more elegant and, in its own right, more general than 1. Is like placing a spotlight farther away so that it lightens a larger area. A lot larger actually. I'm not a mathematician myself but I'm sure they'll find a ton of connections between definition 2 and other mathematical concepts, but not so many related to definition 1 when x is not zero.
In general, you can, and most likely want to return the identity element (the one that leaves the other operand unchanged) whenever you have a function that applies a binary operator over a set of elements and the set is empty. This is the same reason a Product function will return 1 when the list is empty (note that you could just replace "x plus" with "one times" in definition 2). And is the same reason All (which can be thought of as the repeated application of the logical AND operator) will return true when the list is empty (p && true is equivalent to p), and the same reason Any (the OR operator) will return false.
The method cycles through all elements until it finds one that does not satisfy the condition, or finds none that fail. If none fail, true is returned.
So, if there are no elements, true is returned (since there were none that failed)
Here is an extension that can do what OP wanted to do:
static bool All<T>(this IEnumerable<T> source, Func<T, bool> predicate, bool mustExist)
{
foreach (var e in source)
{
if (!predicate(e))
return false;
mustExist = false;
}
return !mustExist;
}
...and as others have pointed out already this is not a bug but well-documented intended behavior.
An alternative solution if one does not wish to write a new extension is:
strs.DefaultIfEmpty().All(str => str == "ABC");
PS: The above does not work if looking for the default value itself!
(Which for strings would be null.)
In such cases it becomes less elegant with something similar to:
strs.DefaultIfEmpty(string.Empty).All(str => str == null);
If you can enumerate more than once the easiest solution is:
strs.All(predicate) && strs.Any();
i.e simply add a check after that there actually were any element.
Keeping the implementation aside. Does it really matter if it is true? See if you have some code which iterates over the enumerable and executes some code. if All() is true then that code is still not going to run since the enumerable doesn't have any elements in it.
var hungryDogs = Enumerable.Empty<Dog>();
bool allAreHungry = hungryDogs.All(d=>d.Hungry);
if (allAreHungry)
foreach (Dog dog in hungryDogs)
dog.Feed(biscuits); <--- this line will not run anyway.

Why isn't this DirectoryInfo comparison working? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to check whether 2 DirectoryInfo objects are pointing to the same directory?
var dirUserSelected = new DirectoryInfo(Path.GetDirectoryName("SOME PATH"));
var dirWorkingFolder = new DirectoryInfo(Path.GetDirectoryName("SAME PATH AS ABOVE"));
if (dirUserSelected == dirWorkingFolder)
{
//this is skipped
}
if (dirUserSelected.Equals(dirWorkingFolder))
{
//this is skipped
}
Whilst debugging, I can examine the values in each and they ARE equal. So i'm guessing this is another byval byref misunderstanding... Please someone, how do I compare these two things?
I believe you want to do this :
var dirUserSelected = new DirectoryInfo(Path.GetDirectoryName(#"c:\some\path\"));
var dirWorkingFolder = new DirectoryInfo(Path.GetDirectoryName(#"c:\Some\PATH"));
if (dirUserSelected.FullName == dirWorkingFolder.FullName )
{ // this will be skipped,
// since the first string contains an ending "\" and the other doesn't
// and the casing in the second differs from the first
}
// to be sure all things are equal;
// either build string like this (or strip last char if its a separator)
// and compare without considering casing (or ToLower when constructing)
var strA = Path.Combine(dirUserSelected.Parent, dirUserSelected.Name);
var strB = Path.Combine(dirWorkingFolder.Parent, dirWorkingFolder.Name);
if (strA.Equals(strB, StringComparison.CurrentCultureIgnoreCase)
{ //this will not be skipped
}
............
In you example you are comparing 2 different objects thats why they are not equal. I believe you need to compare Paths so use the code above.
I did a Google Search for "DirectoryInfo equality" and found several great results, including one on StackOverflow (How to check whether 2 DirectoryInfo objects are pointing to the same directory?)
If two Directory.FullNames match, then you know they are the same, but if they don't match, you still don't know much. There are short names and links and junctions and many other reasons two different strings could refer to the same location on disk.
If you count on knowing for sure that two strings aren't the same location, and security is at stake, you're likely creating a security bug. Tread carefully.
As Jaroslav Jandek says (sorry I can't comment, not enough reputation)
Because it compares those two
instances, not their value (two
references).
And actually it's the same for tons of other cases! For ex
IPAddress ip1 = IPAddress.Parse("192.168.0.1");
IPAddress ip2 = IPAddress.Parse("192.168.0.1");
Both IP addresses represent the same address, but you have two distinct instances of the IPAddress class. So of course "ip1 == ip2" and "ip1.Equals(ip2)" are both false, because they don't point to the same object.
Now if you check "ip1.Address == ip2.Address" the result will be true as IPAddress.Address is a "long", so you're comparing 2 value types. Note that "ip1.ToString() == ip2.ToString()" will also be true even if a string is a reference type not a value type (but strings are really specials).
So indeed in your case you want to compare the FullName property (it's a string so no problem).
You say
Is it only by using the properties, i.e. the .FullName property that you are comparing value rather than instance?
Actually it has more to do with whether the property is a value type or a reference type. Also when comparing reference types, in most cases the comparison will be whether or not they point to the same object, but it's possible to override methods or create operators so that the comparison is done on the content of the objects (again just like Jaroslav Jandek already pointed out).
HTH
Because it compares those two instances, not their value (two references).

Categories

Resources