Show method only under certain conditions - c#

I created a .net extension method that converts an string to an integer and throws an InvalidCastException if the passed string isn't an integer:
public static int ToInt32(this String str)
{
int result;
// string is not a valid 32 bit integer
if (!Int32.TryParse(str, out result))
throw new InvalidCastException();
return result;
}
Is it possible do don't show up / offer the method on the string object if it isn't an integer?

Is it possible do don't show up / offer the method on the string object if it isn't an integer?
No. Even if the parameter were a literal, the C# language doesn't have a mechanism for restricting method overloads according to parameter values. And of course, there's no requirement you can make that the method argument be provided as a literal. A variable or other expression used to provide the argument could be literally any string, and the compiler has no way to identify the nature of the argument (i.e. check whether it could be parsed as an integer).
Depending on what you're trying to do, you might be able to solve the broader problem with a Roslyn code analyzer. That's a whole other "ball of wax" though.

Related

Possible to create case insensitive string class?

What would be required to create a case-insensitive string type that otherwise behaves exactly like a string?
I've never heard of anyone making a case insensitive string type like this and it's obviously not part of the framework, but it seems like it could be very useful. The fact that SQL does case insensitive comparisons by default is a great case in point. So I'm thinking it's either not possible, or else there's a really good reason why no one does it that I'm not aware of.
I know it would require using an implicit operator for assignment, and you would have to override the equals operator. And for overriding GetHashCode(), I'm thinking you could just return ToLower().GetHashCode().
What am I missing?
Comparing string is rather easy. You can simply use the equals method or the compare method.
Example:
string s = "A";
s.Equals("a", StringComparison.InvariantCultureIgnoreCase); // Will return true.
string s = "A";
s.Equals("a", StringComparison.InvariantCulture); // Will return false.
You should also look at this. That will explain a little more on comparing strings.
Building on type of deathismyfriend's answer above, I would extend the string class:
public static class StringExtensions
{
public static int CaseInsensitveCompare(this string s, string stringToCompare)
{
return String.Compare(s, stringToCompare, StringComparison.InvariantCultureIgnoreCase);
}
}
And the call:
int result = firstString.CaseInsensitveCompare(secondString);
It wouldn't behave "exactly like a string". The string type is special and is baked into the language spec. C# strings exhibit special behavior, such as
being a reference type, that gets passed by value. Reference types are normally passed by...well...reference.
are interned by default. That means that there is only ever a single instance of a given string. The following code results in the creation of just a single string: a, b and c all point to exactly the same instance of the string quick. That means that Object.ReferenceEquals() is true when comparing any two:
string a = "The quick brown dog...".Substring(4,5) ;
string b = new string(new char[]{'q','u','i','c','k'});
string c = new StringBuilder().
.Append('q')
.Append('u')
.Append('i')
.Append('c')
.Append('k')
.ToString()
;
[edited to note: while one might think that this should be possible, a little fiddling around suggests that one can't actually create a custom implementation/subtype of CompareInfo as it has no public constructors and its default constructor is internal. More in the answers to this question: Globally set String.Compare/ CompareInfo.Compare to Ordinal
Grrr...]
What you could do is this:
String comparisons are done using the current culture's collation/comparison rules. Create a custom culture for your app, say, a copy of the the US culture that uses the collation/comparison rules you need. Set that as the current culture and Bob's-yer-uncle.
You'll still get compiler/ReSharper whines because you're doing string comparisons without specifying the desired comparison semantics, but your code will be clean.
For more details, see
https://msdn.microsoft.com/en-us/library/kzwcbskc(v=vs.90).aspx
https://msdn.microsoft.com/en-us/library/se513yha(v=vs.100).aspx

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.

C# Best way to convert dynamic to string

The following gets a field from a DataTable and converts it to string. Is there a cleaner way to convert dynamic to string?
dynamic value = dataTable.Rows[i].Field<dynamic>(columnName);
value = (value == null) ? null : value.ToString();
string value = Convert.ToString(dataTable.Rows[i][columnName]);
the standard formatting will kick in, without the need for things like generics, extension methods or dynamic.
First of all as Marc mentioned in his answer "the standard formatting will kick in, without the need for things like generics, extension methods or dynamic" , so in your case you don't have to use dynamic keyword , you can just convert directly to string, but talking about converting from dynamic to string I have two ways:
First way
string x = Convert.ToString(value) // value is a dynamic object
pros: this is a good way of conversion if you are not sure whether the compiled data type supports casting to string or it's hard coded
as int for instance,
cons: this way can cause errors if your are trying to make Convert.ToString(value) // value is a dynamic object inside an Extension Method , when I do so it
gives me this error : "Extension methods cannot be dynamically
dispatched. Consider casting the dynamic arguments or calling the
extension method without the extension method syntax".
so if you are for example using Asp.Net Core HttpContext.Session.SetString()
and you put Convert.ToString(value) // value is dynamic object as an inline conversion in the arguements it will give you the error in the cons secion, to resolve this you can assign a variable outside the function arguments to the Covert.ToString(value) result then send the variable to the extension function arguements :
dynamic value = 10;
HttpContext.Session.SetString("key",Convert.ToString(value)); <-- error
resolve:
dynamic value = 10;
string x = Convert.ToString(value);
HttpContext.Session.SetString("key",x); // works fine
or use the second way (casting), make sure the compiled data type supports casting to string
HttpContext.Session.SetString("key",(string)value);
Second Way
cast dynamic to string if the compiled data type supports it
string x = (string)value; //value is dynamic object
pros: -it's useful if you want to make inline conversion inside an
Extension method arguements
-also useful if you want to make sure that the compiled data type supports casting to string and generate an exception based on this
cons: this doesn't work on all data types so if you want a more generic conversion method the first way is recommended
as mentioned here in MS docs "The dynamic type enables the operations in which it occurs to bypass compile-time type checking. Instead, these operations are resolved at run time."
So the dynamic variable's data type is compiled at run time and takes a type other than dynamic, and you can use casting if the interpreted object supports it or use Convert.ToString() for more generic type conversion.
PS: if you are converting to a data type other than string you may face data loss , like converting float to int , so be aware of that.
I have a case where the dynamic should be a string, but in an error case is a number (code I call into and can't change is doing that).
In my case I do:
string x = value as string;
if (x == null)
{
// error condition
} else {
//use x here
}
Convert.ToString doesn't work for me since my data are double[][] and result will be "System.Double[][]"
double[,] figure_geometry = new double[2, 2] { { 1.0, 1.0 }, { 2.0, 2.0 } };
string geometry = JsonSerializer.Serialize(figure_geometry);
Works well

Why aren't values implicitly convertible to string in C#?

I have some code like:
int value = 5;
MessageBox.Show ( value );
and the MessageBox.Show complains saying:
"cannot convert from 'int' to
'string'"
I seem to remember some cases where values seem to be implicitly converted to string values, but can't recall them exactly.
What's the reason behind this decision that any value isn't implicitly convertible to string values?
MessageBox.Show() only accepts a string. When you use something like Debug.WriteLine, it accepts a bunch of different object types, including object, and then calls ToString() on that object. This is probably what you're experiencing.
A short solution (everywhere you need a string):
MessageBox.Show(""+value);
But I would prefer a ToString() or a String.Format() in most cases.
To answer the "Why" part: because implicit conversions can be dangerous and can undermine type-safety.
"1" + 2 = "12" = 12, not always what you want or expect.
For the exact reason, you would have to ask either the C# compiler guys, or one of the .NET runtime guys.
However, there are no places in the .NET framework or the C# language where values are automatically and implicitly convertible to strings.
You might, however, think of the way string concatenation works, but that only works because there are a lot of overloads on the string.Concat method, including one that takes an object.
In other words, this is allowed:
string s = "Hello there: " + 4;
Other methods around in the framework also has lots of overloads, such as Debug.WriteLine and such, where it will easily accept your integer or decimal, convert it to a string through a call to .ToString, and then print it.
It isn't, however, something built into string or int, but the method itself.
Try
MessageBox.Show(value.ToString());

Why does: string st = "" + 12; work in c# without conversion?

This is super dumb, but I've googled and checked references and I just cannot find an answer... Why can an int or float etc be added as part of a string without converstion but not on it's own? that is:
while this work fine:
string st = "" + 12;
this doesn't (of course):
string st = 12;
Where is the magic here? I know it works I just want to know WHY it works and how I control HOW the conversion is done?
In the first statement, the left operand for the + is a string, and as such + becomes the concatenation operator. The compiler finds the overload for that operator which takes a string and an arbitrary value as operands. This converts both operands to strings (using ToString()) then joins them.
The second statement does not work because there's no implicit cast from int to string.
You can control how the conversion is done by using parentheses to change the order of operations (semi-effective) or by writing code to handle the conversions pre-emptively.
This is how string concatenation is designed to work, and as BoltClock's answer noted, the compiler is using the + as the string concatenation operator. From the C# Language Specification on string concatenation, we find that:
Any non-string argument is converted to its string representation by invoking the virtual ToString method inherited from type object.
String concats in .NET ultimately resolve to calls to one of the overloads of the static String.Concat methods. This is an optimization to reduce the number of temporary strings that would otherwise be created when mutliple concatenations occur in a single statement.
In short the reason this works is because a number of the String.Concat overloads will accept object in the argument list and since an int, float etc. are in essence objects they can be passed to the Concat overload that accepts one or more object parameters. Internally Concat of basically does a .ToString() on the incomming object therefore turning your int into it's string representation.
In your specific example
string st = "" + 12;
The compiler will reconize that the first string is empty and simply call the String.Concat(object) overload. Which will convert the integer 12 to a string and assign it to st.
This overload is called because the integer can be implicitly boxed to fit into the object type and therefore satisfy the method overload selection.
Because the compiler will call .ToString() on all objects if one of the parameters is a string.
This is working because of the operator overload of the operator + on the string datatype.
Because the first is an expression and there C# makes an implicit conversion.
The second is an assignement with a static value, and the static value has no methods to be called.
As long as the value to be asigned is a variable or expression return there will be a toSting method to call.
It's because the compiler translates the addition to a call to String.Concat().
Internally, all operands are boxed (if necessary) and passed to the String.Concat method (which of course calls ToString() on all arguments).

Categories

Resources