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

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).

Related

GetBytes() method returns different array for seemingly same strings

I've got two strings - one is retrieved from the DB and the other is scraped from the web - the two are then compared to check if there's been a change.
The issue is that both strings are seemingly identical, here:
https://m.atcdn.co.uk/a/media/w267h200pdfdfdf/25bc7a46fdb6499db28370ab693f230c.jpg
https://m.atcdn.co.uk/a/media/w267h200pdfdfdf/25bc7a46fdb6499db28370ab693f230c.jpg
However, when I use Encoding.ASCII.GetBytes() on each string, they both return two different byte arrays.
What could be causing this?
The strings you posted are indeed identical, so I think the issue lies somewhere else.
I can think of two possible causes:
You are not comparing the two Arrays the correct way and therefor they appear unequal to you.
var bytes1 = Encoding.ASCII.GetBytes("https://m.atcdn.co.uk/a/media/w267h200pdfdfdf/25bc7a46fdb6499db28370ab693f230c.jpg");
var bytes2 = Encoding.ASCII.GetBytes("https://m.atcdn.co.uk/a/media/w267h200pdfdfdf/25bc7a46fdb6499db28370ab693f230c.jpg");
// This will only compare the Reference of both Arrays, not their content:
var equals = bytes1.Equals(bytes2); // bytes1 == bytes2;
// Compare them like this instead:
var equals = bytes1.SequenceEqual(bytes2);
If you receive the strings from an API or some third party, there might be additional characters like \0 included, that are not visible to the user, but would affect the byte Array.
These are the only two reasons i can think of with the information you've given us.

Simple if between two strings fails [duplicate]

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.

C# Changing a string after it has been created

Okay I know this question is painfully simple, and I'll admit that I am pretty new to C# as well. But the title doesn't describe the entire situation here so hear me out.
I need to alter a URL string which is being created in a C# code behind, removing the substring ".aspx" from the end of the string. So basically I know that my URL, coming into this class, will be something like "Blah.aspx" and I want to get rid of the ".aspx" part of that string. I assume this is quite easy to do by just finding that substring, and removing it if it exists (or some similar strategy, would appreciate if someone has an elegant solution for it if they've thought done it before). Here is the problem:
"Because strings are immutable, it is not possible (without using unsafe code) to modify the value of a string object after it has been created." This is from the MSDN official website. So I'm wondering now, if strings are truly immutable, then I simply can't (shouldn't) alter the string after it has been made. So how can I make sure that what I'm planning to do is safe?
You don't change the string, you change the variable. Instead of that variable referring to a string such as "foo.aspx", alter it to point to a new string that has the value "foo".
As an analogy, adding one to the number two doesn't change the number two. Two is still just the same as it always way, you have changed a variable from referring to one number to refer to another.
As for your specific case, EndsWith and Remove make it easy enough:
if (url.EndsWith(".aspx"))
url = url.Remove(url.Length - ".aspx".Length);
Note here that Remove is taking one string, an integer, and giving us a brand new string, which we need to assign back to our variable. It doesn't change the string itself.
Also note that there is a URI class that you can use for parsing URLs, and it will be able to handle all of the complex situations that can arise, including hashes, query parameters, etc. You should use that to parse out the aspects of a URL that you are interested in.
String immutability is not a problem for normal usage -- it just means that member functions like "Replace", instead of modifying the existing string object, return a new one. In practical terms that usually just means you have to remember to copy the change back to the original, like:
string x = "Blah.aspx";
x.Replace(".aspx", ""); // still "Blah.aspx"
x = x.Replace(".aspx", ""); // now "Blah"
The weirdness around strings comes from the fact that System.String inherits System.Object, yet, because of its immutability, behaves like a value type rather than an object. For example, if you pass a string into a function, there's no way to modify it, unless you pass it by reference:
void Test(string y)
{
y = "bar";
}
void Test(ref string z)
{
z = "baz";
}
string x = "foo";
Test(x); // x is still "foo"
Test(ref x); // x is now "baz"
A String in C# is immutable, as you say. Meaning that this would create multiple String objects in memory:
String s = "String of numbers 0";
s += "1";
s += "2";
So, while the variable s would return to you the value String of numbers 012, internally it required the creation of three strings in memory to accomplish.
In your particular case, the solution is quite simple:
String myPath = "C:\\folder1\\folder2\\myFile.aspx";
myPath = Path.Combine(Path.GetDirectoryName(myPath), Path.GetFileNameWithoutExtension(myPath));
Again, this appears as if myPath has changed, but it really has not. An internal copy and assign took place and you get to keep using the same variable.
Also, if you must preserve the original variable, you could simply make a new variable:
String myPath = "C:\\folder1\\folder2\\myFile.aspx";
String thePath = Path.Combine(Path.GetDirectoryName(myPath), Path.GetFileNameWithoutExtension(myPath));
Either way, you end up with a variable you can use.
Note that the use of the Path methods ensures you get proper path operations, and not blind String replacements that could have unintended side-effects.
String.Replace() will not modify the string. It will create a new one. So the following code:
String myUrl = #"http://mypath.aspx";
String withoutExtension = myUrl.Replace(".aspx", "");
will create a brand-new string which is assigned to withoutExtension.

Best way for comparing string arrays (Custom command line commands)

In my application I am making a custom command line. I am looking for the best way to check user entered commands and argument agains the arguments I have defined. Take the following example command (which works if user enter it right and in order)
do>Drawer /X:Time /Y:Current /N:Window NAme /D:Description
Now I want to have a method to does the checking for me:
private string CheckDrawerArgs(string[] args)
{
var mustExist = new string[4]{"X:", "Y:", "N:", "D:"};
if(args.Length != mustExist.Length)
{
return "Arguments are not completly defined. use 'Drawer /?' for help.";
}
var argsAreRight = false;
var flat = from s1 in args
from s2 in mustExist
where s1.StartsWith(s2)
//how to check if all elements provided
// in args does look
// like (Starts with) elements in mustExist
;
if(argsAreRight == false)
{
return "Bad arguments";
}
//Proceed with rest...
}
So what I am looking for, is to check if required arguments which are provided by user, are in the args also they are not duplicated while the order of them would not effect the checking...
Looking forward for tips!
I would recommend writing it in a more reusable way. The fact that all parameters must be given should not be hard-coded into the logic of the parameter parser. You should just check for that in the end, right before you "proceed with rest".
What I generally do in such cases is the following:
First of all, for each one of the possible arguments I have some variables which contain reasonable defaults (so that the argument can be omitted) a trivial example of which would be bool argument_x_given = false;
So, I loop over the given arguments, and inside the loop I check the current argument against each and every one of the possible arguments, to find which one it is. If not found, we have an error. If a matching argument is found, then I parse the rest of the argument (the stuff after the ':') and I set the variables which are associated with the argument. While doing this, I check to make sure that the argument is not a duplicate. In the trivial example here, that would be if( argument_x_given ) { --error-- } else { argument_x_given = true; ... }.
Finally, once the loop is done, I make sure that all the required arguments were given.
So, what I am trying to say is that you will not gain anything by comparing the string arrays, because you are going to have to make sense out of each and every one of your arguments anyway, and also comparing the string arrays is like trying to take advantage of a situation which is very specific to the problem at hand and not reusable at all.
Further to Henk's answer following is tested and working
var allpresent = args.Length == mustExist.Length && args.All(c =>
mustExist.Any(e =>
c.ToString().StartsWith(e)));
None of the examples provided account for the forward slash characters that each command line argument starts with. You might need to change your mustExist to include the forward slashes:
var mustExist = new string[4]{"/X:", "/Y:", "/N:", "/R:"};
The other option is to strip them off of the args before the comparison.

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.

Categories

Resources