C#: Why does List<String>.Equals(String) compile? - c#

In my Java days I got used to doing .Equals() for comparisons instead of == (at least for cases where I knew / had tested for whether the object I called .Equals() on was not null).
I just ran into a problem with some C#.NET code that had been missed for a few versions because it compiled OK, but at runtime it always returned false, but I'm a bit confused about why it compiled, can somebody please explain? (I'm guessing it maybe has something to do with Equals() being inherited from object, but didn't see a good reference for this).
Story: I had a class I use for filtering database queries, called WorkFilter, and I converted the filter engine to support multi-value filters (as opposed to just single-value filters). So each filter field property of WorkFilter was converted from String to List<String>, and I converted most of the code (except this one case I missed) to deal with this, and it was fine for a while until I noticed that a certain condition was never true.
Filter class looks like this:
public class WorkFilter
{
public List<String> RecordType { get; set; }
public List<String> Product { get; set; }
... etc ...
}
The "bad" code was doing this:
if (workFilterInstance.RecordType != null && workFilterInstance.RecordType.Equals("REQUEST"))
{
// code that never gets fired because List<String> never equals String value
}
I fixed it to do this (basically):
if(workFilterInstance.RecordType != null && workFilterInstance.RecordType.Contains("REQUEST"))
{
// now this can handle logic for RecordType = "REQUEST" filters
}
I was kicking myself because I know that if I had used == instead, it would have failed at compile time, for example, if I did this: RecordType == "REQUEST" because you can't use the equality operator to compare List<String> and String.
But I was surprised by my misunderstanding of .Equals() because I expected RecordType.Equals(String) to also generate a compiler error (or at least a runtime error, instead of always returning false)... I mean, why would you ever compare List<> to String anyway, and why did this compile?
I poked around MSDN a bit but was hoping somebody could explain it in plain english. Thanks!

Because List<T> is an Object and Object provides Equals implementation. Which is defined as:
public virtual bool Equals(
Object obj
)
now since your parameter passed is a string which is again an object, it compiles.
For your comment:
But why would that not fail at runtime? Is there no protection against
doing what I did? –
It will return false. There is no reason for it to fail. (Although IMO, it should show a warning). If you use Resharper you will get a warning:
Suspicious comparison: there is no type in the solution which is
inherited from both

This code compiles because the Equals method of List<T> is an override of the Equals method of System.Object:
public virtual bool Equals(
Object obj
)
It would not fail at runtime because the contract for Equals requires that
x.Equals(y) returns the same value as y.Equals(x).
and System.String's Equals(Object) will return false if it is passed something that is not a string:
true if obj is a String and its value is the same as this instance; otherwise, false.

Yes; it would be nicer if you would get a warning or error for that.
However, the type system is not rich enough to express that.
You want to write
public virtual bool Equals(??? o);
Where ??? means any type convertible to the qualifier on which the method was called.
It should be fairly easy to write a Roslyn diagnostic to catch this.

Related

Did not get compile error when comparing Enum with const int using Equals

C#: Code parts:
class ConstValues
{
public const int NULL=1;
}
class Example
{
private enum FormatFunction
{
Date,
Unknown
}
...
FormatFunction returnValue = fn();
...
Now I have two scenarios.
When I used this way to compare my return code to a value
if (!returnValue.Equals(ConstValues.NULL))
{
...
I get no compile time error (and the code does not work as intended because this is a bug of mine that I missed out).
But when I change to
if (returnValue != ConstValues.NULL)
{
...
I get a compile time error and discover the mistake I did.
I understand that the underlying structure of an enum is int, but I would rather get a compile time error even when using Equals.
Why do the first way pass and the second don't?
It is because default virtual Equals method is receiving object instead of strong typed value like in second example. It is boxed into object and will check types only in runtime.
Why it is made so? The reasoning is pretty funny - for possibility to compare cats and dogs if they walk on all fours. Compare two completely different objects by some almost identical properties.
Thing is, when you can - work with strong typed objects. This will prevent bad things from happening in compile time.
!= is a language convention so this is C# specific. Calling this operator is early bound, in other words, it will occur at compile time.
Equals is a framework convention, .NET in this case, and that is bound at runtime.
When you call !=, the decision is made by the C# compiler during compilation so you get an error. When you call Equals the decision is made by the framework at runtime. Since your enum is not of type object, it will be turned into an object (boxing) and then the runtime will check if your type has overridden the Equals method, since you have not, it will use the default implementation.
Equals for Reference type
If the instance is a reference type, the default implementation of Equals checks if one object reference is the same as the other object reference. If they are the same reference, it returns true. Otherwise it returns false.
Equals for Value type
If the instance is a value type, then it will test for value equality. This is your case. It will check if the enum value you have is equal to the constant value. No error will be shown or thrown: it either equals or it does not.

Why does integer.equals(string) give false when both contain the same value, but does not throw type mismatch exception?

I have code where I get a string as input, and I compare it with an integer.
I saw that integer variable also has an Equals function that accepts a string parameter.
I have used it directly thinking it will typecast it.
It did not give any compile time or runtime error, but it always gives a false result.
For example,
int sessionId = 1;
string requestId="1"
return sessionId.Equals(requestId);
sessionId.Equals(requestId) always gives false.
Why is the reason for such behavior? If there is a reason, why are they allowing it run without error?
Integers and strings are always different, and thus "1".Equals(1) returns false.
It compiles because object.Equals(object other) takes an object as the right side, and thus accepts any type.
The reason why this happens is that a string "0" is not the same as 0, so it returns false.
Why is such behavior supported? Because the Equals method allows you to pass an object as a parameter, and a string is in an object, so you are "allowed" to do it. As you have found, it's not very useful in this case.
To solve your problem either get a string representation of the integer, or parse your string to an integer, then compare.
E.g. Try
return (sessionId.ToString() == requestId);
or
return (sessionId == int.Parse(requestId));
If you choose the later you may need to consider if the Parse could fail and how you might handle that.
Yes, Equals takes any type on the right side because it is requires an object. But inside the function it requires the same type as the left side. IMHO there's no need to throw an exception for type mismatching because one only wants to know about equality of two types.
Decompiled Equals of int:
public override bool Equals(object obj)
{
return obj is int && this == (int)obj;
}
If someone shows you a car and a banana, and asks whether they are the same thing, would you throw a temper tantrum because a car is a vehicle and a banana is a fruit, or would you simply say "no, they are not the same thing"?
In many languages, trying to compare an integer and a string will yield a compiler error, because the compiler knows that the integer and the string cannot possibly be the same thing and thus any code that tried to compare them would almost certainly be erroneous. On the other hand, when you say sessionId.Equals(requestId), the compiler knows that you are asking that requestId be passed to the Int32 override of Equals. Since that override can accept a reference to any kind of heap object, it has no problem passing the string "1". That method in turn knows that it was given something which isn't the same as an Int32 with the value 1. It doesn't know that the calling code can't possibly supply anything that would match an Int32; all it knows is that the particular value isn't the same, and because the value isn't the same it perfectly happily returns false.
Shouldn’t we be using String.Compare for string comparison and forget about Equals?
I did have the same problem and I believe the function Equals should throw an exception. In my case, I have been comparing a string with a Boolean.
The discussion by now went wrong way. This is my view:
If a comparison between objects belonging to two different classes always returns false, then they do not need to be compared in the first place.
If there is a need to have a function that bypasses type checking, there should be one. However, having the function Equals positioned as a recommended method for string comparison and in the same time introducing the possibility of unneeded bugs (which may sit in your program for eternity) is a kind of irresponsible.
Moreover, it is extremely misleading that the function call String.Equals(string1, string2, StringComparison. xxx) also accepts non-string arguments. Thus not only string1.Equals(string2).
If that is by design, then it is a poor design.

usages of out parameter in conditional flow and CA1002 fxcop error

I have a xml parsing code where I am parsing multiple nodes and attributes from xml. Using short circuit, I am able to avoid if in my code because I want to continue processing only in positive case. But I am getting fxcop error CA1002 for parameter as out usages.
How can I remove the fxcorp error?
public bool parseNode()
{
bool success = false;
string val1;
string val2;
string val3
success = TryGetAttributeValue(attribName1, out val1) &&
TryGetAttributeValue(attribName2, out val2) &&
TryGetAttributeValyue(attribName3, out val3);
if(success)
{
// do work
}
}
public bool TryGetAttributeValue(string attribName, out string value)
{
}
Assuming you're talking about CA1021 (Avoid out parameters) and not CA1002 (Do not expose generic lists), FxCop is complaining about the out parameter of your TryGetAttributeValue() method.
You can refactor that method so it returns the attribute value instead of storing it in an out parameter, and have it return nullif the attribute does not exist. From there, you can use the null-coalescing operator ?? to keep the same control flow:
public string TryGetAttributeValue(string attribName)
{
// Return attribute value, or null.
}
public bool ParseNode()
{
if ((TryGetAttributeValue(attribName1)
?? TryGetAttributeValue(attribName2)
?? TryGetAttributeValue(attribName3)) != null) {
// Do work.
}
}
Are you sure it's CA1002? Because that one is the Do not expose generic lists rule according to google. Anyway, I know that FxCop has rule which warns about using out (and also ref) parameters as they are not considered best practice for OO (your are supposed to return a object which represents the result).
In order to get rid of the warning you would need to change your method TryGetAttributeValue to not use out parameters.
As a side note: Microsoft apparently violated this rule in the various TryGet and TryParse methods. So just because FxCop says so, it does not make it necessarily a bad choice.
Assuming you are actually talking about CA1021, which fits your description better: This is the MSDN article about this violation. You can change the method type to something other than public or protected (internal ?)
Otherwise:
To fix a violation of this rule that is caused by a value type, have
the method return the object as its return value. If the method must
return multiple values, redesign it to return a single instance of an
object that holds the values.
If you are not able/willing to change the protection type or change the code to simply return the string, then you will have to ignore this fxcop rule . Which, is not a horrible thing. You have to decide which rules seem pertinent and which do not.
Your code would have to be something like GetAttributeValue, and use a check for null if you want to avoid this fxcop rule. Or, you could create a special class and use a Null object pattern, but that seems to be way too much overkill.
In the end, you are in control of your code, and not all rules are meant for everybody.
If you read the whole article, you can see at the end the following:
Methods that implement the Try pattern, such as
Int32.TryParse, do not raise this violation.
So as long as your methode return a bool and has a name like TryGetSomething, you are not violating the rule if you use the out parameter.

How can I use code contracts to check the value of a Lazy<T> without losing the advantages of lazy evaluation?

I have code that looks something like this:
public class Foo
{
private readonly Lazy<string> lazyBar;
public Foo()
{
lazyBar = new Lazy<string>(() => someExpression);
}
public string Bar
{
get { return lazyBar.Value; }
}
public void DoSomething()
{
Contract.Requires(Bar != null); // This evaluates Bar, but all I really require is that WHEN Bar is evaluated, it is not null.
...
}
}
Now, every place DoSomething is called, we must also prove that Bar is not null. But won't checking for this eliminate the benefit of lazy evaluation? Additionally, aren't we supposed to avoid side-effects in our contracts?
Is it possible to prove that someExpression will not resolve to null, without evaluating it?
Code Contracts doesn't have enough insight into Lazy<T> in order to make the connection between the original lambda and the result you get back.
What you really want to be able to state (for Lazy<T>) is that any contracts that hold about the lambda's return value also hold about the Value value, but meta-level contracts like this aren't possible at the moment.
What you could do is move someExpression into a method and then have a Contract.Ensures that result != null. This will then warn you if this condition does not hold. You can then put an Invariant onto the result; lazyBar.Value != null. This will mean that it isn't actually lazy, but for your release code you can build with CC in ReleaseRequires mode and these types of check will be eliminated (having a read in the manual of the different 'levels' of contract enforcement is highly recommended!)
After you edited in your comment in the code I can answer your question, but I don't think I'm answering the exact question lurking in the shadows here, you be the judge.
The only way to know what the property would resolve to if you read from it, is to actually read from it, evaluating the expression you constructed the underlying Lazy<T> field with.
Now, what you can do, is to check the underlying field to ask if it has been evaluated.
You can, in other words, do this:
if (lazyBar.IsValueCreated)
....
Now, whether that will work with a contract I'm not sure, but the following thing should allow you to check:
Contract.Requires(!lazyBar.IsValueCreated || lazyBar.Value != null);
Since I am not an expert on contracts, I don't know if the above code will be turned into an expression tree and evaluated either way.
This partly depends on the type that you're dealing.
For example, types that inherit from ICollection will not be itterated over in order to evaluate such methods as Count().
In the case where ICollection is implimented, the Count() method is optimised to check the Count property.
If you simply want to check that your Lazy object has "something" inside I suggest using the Any() method available to us in the System.Linq namespace.
This will then only need to do a single MoveNext in the collection before being able to determine whether there is "anything" inside it.
I can't understand why this doesn't work (and it really doesn't):
public class Foo
{
private readonly Lazy lazyBar;
public Foo()
{
lazyBar = new Lazy<string>(() => someExpression);
Contract.Ensures(!lazyBar.IsValueCreated);
}
[ContractInvariantMethod]
private static void Invariant()
{
Contract.Invariant(!lazyBar.IsValueCreated || lazyBar.Value != null);
}
public void DoSomething()
{
Contract.Assume(lazyBar.IsValueCreated);
lazyBar.Value.AccessSomeMethod; //Here Code Contracts detect "Possibly calling a method on a null reference"
...
}
}

Mark parameters as NOT nullable in C#/.NET?

Is there a simple attribute or data contract that I can assign to a function parameter that prevents null from being passed in C#/.NET? Ideally this would also check at compile time to make sure the literal null isn't being used anywhere for it and at run-time throw ArgumentNullException.
Currently I write something like ...
if (null == arg)
throw new ArgumentNullException("arg");
... for every argument that I expect to not be null.
On the same note, is there an opposite to Nullable<> whereby the following would fail:
NonNullable<string> s = null; // throw some kind of exception
There's nothing available at compile-time, unfortunately.
I have a bit of a hacky solution which I posted on my blog recently, which uses a new struct and conversions.
In .NET 4.0 with the Code Contracts stuff, life will be a lot nicer. It would still be quite nice to have actual language syntax and support around non-nullability, but the code contracts will help a lot.
I also have an extension method in MiscUtil called ThrowIfNull which makes it a bit simpler.
One final point - any reason for using "if (null == arg)" instead of "if (arg == null)"? I find the latter easier to read, and the problem the former solves in C doesn't apply to C#.
I know I'm incredibly late to this question, but I feel the answer will become relevant as the latest major iteration of C# comes closer to release, then released. In C# 8.0 a major change will occur, C# will assume all types are considered not null.
According to Mads Torgersen:
The problem is that null references are so useful. In C#, they are the
default value of every reference type. What else would the default
value be? What other value would a variable have, until you can decide
what else to assign to it? What other value could we pave a freshly
allocated array of references over with, until you get around to
filling it in?
Also, sometimes null is a sensible value in and of itself. Sometimes
you want to represent the fact that, say, a field doesn’t have a
value. That it’s ok to pass “nothing” for a parameter. The emphasis is
on sometimes, though. And herein lies another part of the problem:
Languages like C# don’t let you express whether a null right here is a
good idea or not.
So the resolution outlined by Mads, is:
We believe that it is more common to want a reference not to be null. Nullable reference types
would be the rarer kind (though we don’t have good data to tell us by
how much), so they are the ones that should require a new annotation.
The language already has a notion of – and a syntax for – nullable value types. The analogy between the two would make the language
addition conceptually easier, and linguistically simpler.
It seems right that you shouldn’t burden yourself or your consumer with cumbersome null values unless you’ve actively decided that you
want them. Nulls, not the absence of them, should be the thing that
you explicitly have to opt in to.
An example of the desired feature:
public class Person
{
public string Name { get; set; } // Not Null
public string? Address { get; set; } // May be Null
}
The preview is available for Visual Studio 2017, 15.5.4+ preview.
I know this is a VERY old question, but this one was missing here:
If you use ReSharper/Rider you may use the Annotated Framework.
Edit: I just got a random -1 for this answer. That's fine. Just be aware it is still valid, even though it's not the recommended approach for C#8.0+ projects anymore (to understand why, see Greg's answer).
Check out the validators in the enterprise library. You can do something like :
private MyType _someVariable = TenantType.None;
[NotNullValidator(MessageTemplate = "Some Variable can not be empty")]
public MyType SomeVariable {
get {
return _someVariable;
}
set {
_someVariable = value;
}
}
Then in your code when you want to validate it:
Microsoft.Practices.EnterpriseLibrary.Validation.Validator myValidator = ValidationFactory.CreateValidator<MyClass>();
ValidationResults vrInfo = InternalValidator.Validate(myObject);
not the prettiest but:
public static bool ContainsNullParameters(object[] methodParams)
{
return (from o in methodParams where o == null).Count() > 0;
}
you could get more creative in the ContainsNullParameters method too:
public static bool ContainsNullParameters(Dictionary<string, object> methodParams, out ArgumentNullException containsNullParameters)
{
var nullParams = from o in methodParams
where o.Value == null
select o;
bool paramsNull = nullParams.Count() > 0;
if (paramsNull)
{
StringBuilder sb = new StringBuilder();
foreach (var param in nullParams)
sb.Append(param.Key + " is null. ");
containsNullParameters = new ArgumentNullException(sb.ToString());
}
else
containsNullParameters = null;
return paramsNull;
}
of course you could use an interceptor or reflection but these are easy to follow/use with little overhead
Ok this reply is a bit late, but here is how I am solving it:
public static string Default(this string x)
{
return x ?? "";
}
Use this exension method then you can treat null and empty string as the same thing.
E.g.
if (model.Day.Default() == "")
{
//.. Do something to handle no Day ..
}
Not ideal I know as you have to remember to call default everywhere but it is one solution.

Categories

Resources