Can somebody answer me this - why do I get this warning "The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type 'int?'"
Here is the code
private char classLetter;
public char ClassLetter
{
get { return classLetter; }
set
{
if (classLetter == null)
{
classLetter = value;
RaisePropertyChanged("ClassLetter");
}
else throw new ArgumentOutOfRangeException();
}
}
If I use this code no warning comes in
private char classLetter;
public char ClassLetter
{
get { return classLetter; }
set
{
if (classLetter.ToString() == null)
{
classLetter = value;
RaisePropertyChanged("ClassLetter");
}
else throw new ArgumentOutOfRangeException();
}
}
In short my question is this
How can a int warning be given for a char variable?
EDIT: The 'char' should hold any latin or Cyrillic Letter, no special symbols and no numbers allowed. How should that be filtered?
In the first case, classLetter is of type char, which can never be null because it's a value type; it would need to be of type char?. So comparing classLetter == null doesn't make sense, as the compiler says.
In the second case, imagine classLetter is 'x'. When doing classLetter.ToString() you get "x", which can be compared with null because it is now a reference type. But again, this is not what you want because classLetter.ToString() will never be null.
If what you want is allowing to set the value only once, you can do this:
private char? classLetter = null; // make it nullable
public char ClassLetter
{
get {
if(classLetter == null) { // if we don't have a value yet
// do something, like throwing an exception
}else{ // if we do have a value already
return classLetter.Value; // here we return char, not char?
}
}
set
{
if (classLetter == null) {
classLetter = value;
RaisePropertyChanged("ClassLetter");
}
else throw new ArgumentOutOfRangeException();
}
}
A variable of type char is a value variable, not a reference variable, so it can never be null. Only variables of reference types can be null.
You get a warning because a value type will never be null. Full(er) explanation below.
A char in C# is a value type, and can never be null. Consider the purpose of char, that is to represent a Unicode character. There isn't really a good value to pick to mean null in the 0x0 to 0xFFFFFFFF range. (It's true that UTF-16 doesn't actually encompass this entire range, but it might someday).
It's a bit easy to understand with something that has a much smaller range. Consider a byte. It has a range of 0 - 255. Now, in order to represent null, we would need to pick a manner in which null could be stored. A few solutions end up coming up:
Store information extra to the byte to represent null. Nullable<Byte> does this.
Pick a value in the valid byte range to instead actually mean null. You end up needing to check for this value throughout an entire program. On a small scale, this is a non-issue, but when you don't know who's going to be using your code (a likely scenario), it's something you have to document and hope they see.
It's a much simpler implementation to provided non-nullable value types and a default and provide a wrapper around value types that can represent null if needed. .NET does exactly this with the Nullable<T> type and it's shortcuts with language support (int?,byte?, etc.).
To address your code, if classLetter really could be any value a char can represent, then you can use:
private char classLetter;
public char ClassLetter
{
get { return classLetter; }
set
{
classLetter = value;
RaisePropertyChanged("ClassLetter");
}
}
You can do this because the compiler will give the user a compile-time error if they try to do something to classLetter they couldn't possibly do sanely.
If you have additional requirement about what classLetter is supposed to represent, update your question and I'll update my answer.
In reponse to your comment on another answer: "I want the behavior to be simple. I want to be able to put any symbol, but I don't want the variable to be left empty"
The only other thing we need to settle on is what "empty" really means. What does empty mean in your context? Once you answer that, you can use default initialization in the type containing classLetter to set it to that value. A generalized example:
class Foo {
private char classLetter;
public char ClassLetter {
get { return classLetter; }
set {
classLetter = value;
}
}
public Foo(char classLetter = 'A') {
this.ClassLetter = classLetter;
}
}
When a caller uses new Foo(), they will get a Foo instance where Foo.ClassLetter == 'A'. Of course, A can be any sensible default that meets your specific requirements.
Is this what you want?
private char? classLetter;
public char ClassLetter
{
get { return classLetter.Value; // this will throw exception, if value hasn't set }
set
{
if (classLetter != null)
{
throw new InvalidOperationException("ClassLetter has been set already.");
}
classLetter = value;
RaisePropertyChanged("ClassLetter");
}
}
Note, that ArgumentOutOfRangeException doesn't fit this case. You don't make any tests for the range of argument.
Related
I like to use pattern-matching on a nullable int i.e. int?:
int t = 42;
object tobj = t;
if (tobj is int? i)
{
System.Console.WriteLine($"It is a nullable int of value {i}");
}
However, this results in the following syntax errors:
CS1003: Syntax error, ';',
CS1525: Invalid expression term ')',
CS0103: The name 'i' does not exist in the current context.
'i)' is marked with a red squiggly line.
The expression compiles when using the old operator is:
int t = 42;
object tobj = t;
if (tobj is int?)
{
System.Console.WriteLine($"It is a nullable int");
}
string t = "fourty two";
object tobj = t;
if (tobj is string s)
{
System.Console.WriteLine($#"It is a string of value ""{s}"".");
}
Also works as expected.
(I'm using c#-7.2 and tested with both .net-4.7.1 and .net-4.6.1)
I thought it had something to with operator precedence. Therefore, I have tried using parenthesis at several places but this didn't help.
Why does it give these syntax errors and how can I avoid them?
The type pattern in its various forms: x is T y, case T y etc, always fails to match when x is null. This is because null doesn't have a type, so asking "is this null of this type?" is a meaningless question.
Therefore t is int? i or t is Nullable<int> i makes no sense as a pattern: either t is an int, in which case t is int i will match anyway, or it's null, in which case no type pattern can result in a match.
And that is the reason why t is int? i or t is Nullable<int> i are not, and probably never will be, supported by the compiler.
The reason why you get additional errors from the compiler when using t is int? i is due to the fact that, e.g. t is int? "it's an int" : "no int here" is valid syntax, thus the compiler gets confused over your attempts to use ? for a nullable type in this context.
As to how can you avoid them, the obvious (though probably not very helpful) answer is: don't use nullable types as the type in type patterns. A more useful answer would require you to explain why you are trying to do this.
Change your code into:
int t = 42;
object tobj = t;
if (tobj is Nullable<int> i)
{
Console.WriteLine($"It is a nullable int of value {i}");
}
This produces the more helpful:
CS8116: It is not legal to use nullable type 'int?' in a pattern; use the underlying type 'int' instead (Could not find documentation about CS8116 to reference)
Others (user #Blue0500 at github ) have tagged this behaviour as a bug Roslyn issue #20156. Reacting to Roslyn issue #20156, Julien Couvreur from Microsoft has said he thinks it is by design.
Neal Gafter from Microsoft working on Roslyn has also said better diagnostics are wanted for use of nullable type is switch pattern.
So, the error message can be avoided by using:
int t = 42;
object tobj = t;
if (tobj == null)
{
Console.WriteLine($"It is null");
}
else if (tobj is int i)
{
Console.WriteLine($"It is a int of value {i}");
}
Except for issues when parsing tobj is int? i, this still leaves the question why is tobj is int? i or tobj is Nullable<int> i not allowed.
For anyone wondering how to actually use pattern matching with nullables, you can do so with a generic helper function, like so:
public static bool TryConvert<T>(object input, out T output)
{
if (input is T result)
{
output = result;
return true;
}
output = default(T);
// Check if input is null and T is a nullable type.
return input == null && System.Nullable.GetUnderlyingType(typeof(T)) != null;
}
This will return true if T is a nullable or non-nullable of the same type that input contains or if input is null and T is nullable. Basically works the same as normal, but also handles nullables.
Side note: Interestingly, from my testing, I found System.Nullable.GetUnderlyingType(typeof(T)) allocates 40 bytes of garbage every time it's called if T is nullable. Not sure why, seems like a bug to me, but that's potentially a hefty price to pay rather than just null-checking like normal.
Knowing that, here's a better function:
public static bool TryConvert<T>(object input, out T? output) where T : struct
{
if (input is T result)
{
output = result;
return true;
}
output = default(T?);
return input == null;
}
I have a very simple if statement but it always returns false never true.
Here is my if statement
if (objectValue.Equals(intValue))
{
return true;
}
return false;
Do I need to cast my objectValue variable to an int before comparing them?
Since Equals is a virtual method it will call the appropriate method of the subclass of object. In this case int.Equals. In a very simple example:
object o = 4;
int i = 4;
o.Equals(i) returns true. So your problem is somewhere else. Maybe objectValue is not an int, but a byte, short or other numerical type.
The problem isn't with having the int boxed in an object - that works just fine, as you can easily try yourself.
The problem only appears when the object doesn't actually contain an int, but rather a different numerical type, e.g. short or byte - in that case, you have to first unbox it to the correct type (for example, (short)objectValue) and then do the comparison. Unboxing a boxed short to int results in InvalidCastException - you have to use the exact type with value-types.
Also, there's usually no need to use Equals for that - just do (int)objectValue == intValue or so.
int val;
if (int.TryParse(objectValue.ToString(), out val))
{
if (val == intValue)
{
// return true;
}
else
{
//return false;
}
}
else
{
// value of obj is not int. you know here something is wrong
}
Using TryParse() method would be safer option even if you have non int value in the objectValue.
Yes you need to cast it
return ((int)objectValue).Equals(intValue);
without the cast a type comparison will be performed and object is never equal to an int, thats why you get the false value.
I want to check if a variable is initialized at run time, programmatically. To make the reasons for this less mysterious, please see the following incomplete code:
string s;
if (someCondition) s = someValue;
if (someOtherCondition) s = someOtherValue;
bool sIsUninitialized = /* assign value correctly */;
if (!sIsUninitialized) Console.WriteLine(s) else throw new Exception("Please initialize s.");
And complete the relevant bit.
One hacky solution is to initialize s with a default value:
string s = "zanzibar";
And then check if it changed:
bool sIsUninitialized = s == "zanzibar";
However, what if someValue or someOtherValue happen to be "zanzibar" as well? Then I have a bug. Any better way?
Code won't even compile if the compiler knows a variable hasn't been initialized.
string s;
if (condition) s = "test";
// compiler error here: use of unassigned local variable 's'
if (s == null) Console.Writeline("uninitialized");
In other cases you could use the default keyword if a variable may not have been initialized. For example, in the following case:
class X
{
private string s;
public void Y()
{
Console.WriteLine(s == default(string)); // this evaluates to true
}
}
The documentation states that default(T) will give null for reference types, and 0 for value types. So as pointed out in the comments, this is really just the same as checking for null.
This all obscures the fact that you should really initialize variables, to null or whatever, when they are first declared.
With C# 2.0, you have the Nullable operator that allows you to set an initial value of null for heretofore value types, allowing for such things as:
int? x = null;
if (x.HasValue)
{
Console.WriteLine("Value for x: " + num.Value);
}
Which yields:
"Value for x: Null".
Just assign it null by default, not a string value
Here's one way:
string s;
if (someCondition) { s = someValue; }
else if (someOtherCondition) { s = someOtherValue; }
else { throw new Exception("Please initialize s."); }
Console.WriteLine(s)
This might be preferable for checking if the string is null, because maybe someValue is a method that can sometimes return null. In other words, maybe null is a legitimate value to initialize the string to.
Personally I like this better than an isInitialized flag. Why introduce an extra flag variable unless you have to? I don't think it is more readable.
You can keep a separate flag that indicates that the string has been initialized:
string s = null;
bool init = false;
if (conditionOne) {
s = someValueOne;
init = true;
}
if (conditionTwo) {
s = someValueTwo;
init = true;
}
if (!init) {
...
}
This will take care of situations when s is assigned, including the cases when it is assigned null, empty string, or "zanzibar".
Another solution is to make a static string to denote "uninitialized" value, and use Object.ReferenceEquals instead of == to check if it has changed. However, the bool variable approach expresses your intent a lot more explicitly.
I would agree with Vytalyi that a default value of null should be used when possible, however, not all types (like int) are nullable. You could allocate the variable as a nullable type as explained by David W, but this could break a lot of code in a large codebase due to having to refine the nullable type to its primitive type before access.
This generic method extension should help for those who deal with large codebases where major design decisions were already made by a predecessor:
public static bool IsDefault<T>(this T value)
=> ((object) value == (object) default(T));
If you are staring from scratch, just take advantage of nullable types and initialize it as null; that C# feature was implemented for a reason.
I pick initialization values that can never be used, typical values include String.Empty, null, -1, and a 256 character random string generator .
In general, assign the default to be null or String.Empty. For situations where you cannot use those "empty" values, define a constant to represent your application-specific uninitialized value:
const string UninitializedString = "zanzibar";
Then reference that value whenever you want to initialize or test for initialization:
string foo = UnininitializedString;
if (foo == UninitiaizedString) {
// Do something
}
Remember that strings are immutable constants in C# so there is really only one instance of UninitializedString (which is why the comparison works).
I've got a generic type T. Using Marc's Operator class I can perform calculations on it.
Is it possible to detect by mere calculations whether the type is an integral or a nonintegral type?
Perhaps there is a better solution? I'd prefer to support any possible type, so I'd like to prevent hard-coding which types are integral/nonintegral.
Background info
The situation I find myself in is I want to cast a double to T but round to the nearest value of T to the double value.
int a = (int)2.6 results in 2 while I want it to result it in 3, without knowing the type (in this case int). It could also be double, in which case I want the outcome to be 2.6.
Have you tried Convert.ChangeType? Something like:
Convert.ChangeType(1.9d, typeof (T))
It will work for all numeric types I think (as long as the first parameter is iConvertible and the type is a supported one which all basic numerics should be I believe).
Its important to mention that this will call something like double.ToInt32 which rounds values rather than truncates (bankers rounding I believe).
I tested this in a little LinqPad program and it does what I think you want:
void Main()
{
var foo = RetNum<decimal>();
foo.Dump();
}
public static T RetNum<T>()
{
return (T)Convert.ChangeType(1.9d, typeof (T));
}
Here's a method which will determine if a particular value stored in a generic numeric type is an integer without hardcoding. Tested working for me on .NET 4. Correctly handles all built in numeric types (as defined in the MSDN link at the bottom) except BigInteger, which doesn't implement IConvertible.
public static bool? IsInteger<T>(T testNumber) where T : IConvertible
{
// returns null if T is non-numeric
bool? isInt = null;
try
{
isInt = testNumber.ToUInt64(CultureInfo.InvariantCulture) == testNumber.ToDouble(CultureInfo.InvariantCulture);
}
catch (OverflowException)
{
// casting a negative int will cause this exception
try
{
isInt = testNumber.ToInt64(CultureInfo.InvariantCulture) == testNumber.ToDouble(CultureInfo.InvariantCulture);
}
catch
{
// throw depending on desired behavior
}
}
catch
{
// throw depending on desired behavior
}
return isInt;
}
Here's a method which will determine whether a particular type is an integral type.
public static bool? IsIntegerType<T>() where T : IConvertible
{
bool? isInt = null;
try
{
isInt = Math.Round((double)Convert.ChangeType((T)Convert.ChangeType(0.1d, typeof(T)),typeof(double)), 1) != .1d;
// if you don't round it and T is float you'll get the wrong result
}
catch
{
// T is a non numeric type, or something went wrong with the activator
}
return isInt;
}
Convert.ChangeType is the way to convert, with rounding, between two generic numeric types. But for kicks and curiosity, here's a way to convert a generic numeric type to an int, which could be extended to return a generic type without too much difficulty.
public static int GetInt32<T>(T target) where T : IConvertible
{
bool? isInt = IsInteger<T>(target);
if (isInt == null) throw new ArgumentException(); // put an appropriate message in
else if (isInt == true)
{
try
{
int i = target.ToInt32(CultureInfo.InvariantCulture);
return i;
}
catch
{ // exceeded size of int32
throw new OverflowException(); // put an appropriate message in
}
}
else
{
try
{
double d = target.ToDouble(CultureInfo.InvariantCulture);
return (int)Math.Round(d);
}
catch
{ // exceeded size of int32
throw new OverflowException(); // put an appropriate message in
}
}
}
My results:
double d = 1.9;
byte b = 1;
sbyte sb = 1;
float f = 2.0f;
short s = 1;
int i = -3;
UInt16 ui = 44;
ulong ul = ulong.MaxValue;
bool? dd = IsInteger<double>(d); // false
bool? dt = IsInteger<DateTime>(DateTime.Now); // null
bool? db = IsInteger<byte>(b); // true
bool? dsb = IsInteger<sbyte>(sb); // true
bool? df = IsInteger<float>(f); // true
bool? ds = IsInteger<short>(s); // true
bool? di = IsInteger<int>(i); // true
bool? dui = IsInteger<UInt16>(ui); // true
bool? dul = IsInteger<ulong>(ul); // true
int converted = GetInt32<double>(d); // coverted==2
bool? isd = IsIntegerType<double>(); // false
bool? isi = IsIntegerType<int>(); // true
Additionally, this MSDN page has some example code which might be helpful. Specifically, it includes a list of types considered to be numeric.
I'm not 100% sure what you're asking, but:
To check if it's an integral type, use this: if (obj is float || obj is double), or if typeof(T) == typeof(float) || typeof(T) == typeof(double))
To check if it's an integral value, cast it to a double, and then do if(value == Math.Round(value))
Of course, that is assuming that you have a number in the first place. I believe that the Operator class you're using supports things like DateTime. Would it be better to make your generic method have a generic constraint where T : IConvertible? That way there'd be explicit ToDouble and ToInteger methods.
Edit:
I think I understand: you've got two local variables, double d; T num;. You want to cast d to type T, but with proper rounding if T is a integral type. Is that correct?
Assuming that's correct, here's what I'd do:
public void SomeMethod<T>()
{
double d;
// I think I got all the floating-point types. There's only a few, so we can test for them explicitly.
if(typeof(T) != typeof(double) && typeof(T) != typeof(float) && typeof(T) != typeof(Decimal))
{
d = Math.Round(d);
}
T converted = Convert.ChangeType(d, typeof(T));
}
Chris's answer gives a possible solution to the scenario I mentioned, but for performance reasons I am still attempting to answer the actual question.
The assumption (untested) is, Convert.ChangeType is much slower than Math.Round(). Ideally, I can check one time whether the given type is integral or not, and conditionally call Math.Round() from then on to obtain a much more efficient solution than calling Convert.ChangeType() constantly.
I'm attempting the following implementation:
Convert both 3, 2 and 1 to the desired unknown type. (This assumes a conversion from an int to the numeric type is possible, which should always be possible anyhow.)
In case 3 / 2 == 1, it is an integral type. Otherwise, it is a nonintegral type.
This solution doesn't rely anywhere on knowing the type and solely uses conversions and calculations.
This is probably trivial, but I can't think of a better way to do it. I have a COM object that returns a variant which becomes an object in C#. The only way I can get this into an int is
int test = int.Parse(string.Format("{0}", myobject))
Is there a cleaner way to do this? Thanks
You have several options:
(int) — Cast operator. Works if the object already is an integer at some level in the inheritance hierarchy or if there is an implicit conversion defined.
int.Parse()/int.TryParse() — For converting from a string of unknown format.
int.ParseExact()/int.TryParseExact() — For converting from a string in a specific format
Convert.ToInt32() — For converting an object of unknown type. It will use an explicit and implicit conversion or IConvertible implementation if any are defined.
as int? — Note the "?". The as operator is only for reference types, and so I used "?" to signify a Nullable<int>. The "as" operator works like Convert.To____(), but think TryParse() rather than Parse(): it returns null rather than throwing an exception if the conversion fails.
Of these, I would prefer (int) if the object really is just a boxed integer. Otherwise use Convert.ToInt32() in this case.
Note that this is a very general answer: I want to throw some attention to Darren Clark's response because I think it does a good job addressing the specifics here, but came in late and wasn't voted as well yet. He gets my vote for "accepted answer", anyway, for also recommending (int), for pointing out that if it fails (int)(short) might work instead, and for recommending you check your debugger to find out the actual runtime type.
The cast (int) myobject should just work.
If that gives you an invalid cast exception then it is probably because the variant type isn't VT_I4. My bet is that a variant with VT_I4 is converted into a boxed int, VT_I2 into a boxed short, etc.
When doing a cast on a boxed value type it is only valid to cast it to the type boxed.
Foe example, if the returned variant is actually a VT_I2 then (int) (short) myObject should work.
Easiest way to find out is to inspect the returned object and take a look at its type in the debugger. Also make sure that in the interop assembly you have the return value marked with MarshalAs(UnmanagedType.Struct)
Convert.ToInt32(myobject);
This will handle the case where myobject is null and return 0, instead of throwing an exception.
Use Int32.TryParse as follows.
int test;
bool result = Int32.TryParse(value, out test);
if (result)
{
Console.WriteLine("Sucess");
}
else
{
if (value == null) value = "";
Console.WriteLine("Failure");
}
Maybe Convert.ToInt32.
Watch out for exception, in both cases.
var intTried = Convert.ChangeType(myObject, typeof(int)) as int?;
I am listing the difference in each of the casting ways. What a particular type of casting handles and it doesn't?
// object to int
// does not handle null
// does not handle NAN ("102art54")
// convert value to integar
int intObj = (int)obj;
// handles only null or number
int? nullableIntObj = (int?)obj; // null
Nullable<int> nullableIntObj1 = (Nullable<int>)obj; // null
// best way for casting from object to nullable int
// handles null
// handles other datatypes gives null("sadfsdf") // result null
int? nullableIntObj2 = obj as int?;
// string to int
// does not handle null( throws exception)
// does not string NAN ("102art54") (throws exception)
// converts string to int ("26236")
// accepts string value
int iVal3 = int.Parse("10120"); // throws exception value cannot be null;
// handles null converts null to 0
// does not handle NAN ("102art54") (throws exception)
// converts obj to int ("26236")
int val4 = Convert.ToInt32("10120");
// handle null converts null to 0
// handle NAN ("101art54") converts null to 0
// convert string to int ("26236")
int number;
bool result = int.TryParse(value, out number);
if (result)
{
// converted value
}
else
{
// number o/p = 0
}
There's also TryParse.
From MSDN:
private static void TryToParse(string value)
{
int number;
bool result = Int32.TryParse(value, out number);
if (result)
{
Console.WriteLine("Converted '{0}' to {1}.", value, number);
}
else
{
if (value == null) value = "";
Console.WriteLine("Attempted conversion of '{0}' failed.", value);
}
}
Strange, but the accepted answer seems wrong about the cast and the Convert in the mean that from my tests and reading the documentation too it should not take into account implicit or explicit operators.
So, if I have a variable of type object and the "boxed" class has some implicit operators defined they won't work.
Instead another simple way, but really performance costing is to cast before in dynamic.
(int)(dynamic)myObject.
You can try it in the Interactive window of VS.
public class Test
{
public static implicit operator int(Test v)
{
return 12;
}
}
(int)(object)new Test() //this will fail
Convert.ToInt32((object)new Test()) //this will fail
(int)(dynamic)(object)new Test() //this will pass
You can first cast object to string and then cast the string to int;
for example:
string str_myobject = myobject.ToString();
int int_myobject = int.Parse(str_myobject);
this worked for me.
int i = myObject.myField.CastTo<int>();
This worked for me, returning 0 also when myobject contains a DBNull
int i = myobject.ToString().Cast<int>().FirstOrDefault();