Generic fails when converting int to bool - c#

I've the following method to search in Registry (don't worry, it's a test using generics):
private static T GetValue<T>(RegistryKey key, string name)
{
using (key)
{
return (T)key.GetValue(name);
}
}
But when using type : Nullable<bool> it fails because of an invalid cast.
(I tried on numeric keys only)
What I want is to have null if key not exists, false if 0 is stored in, or true else.
How can I achieve that?
Thanks !

because generics cannot utilize type-specific behavior, casts to or from a generic type parameter are assumed to be upcasts/downcasts.
a downcast fails here, you need a conversion.
you can try the Convert class, but better to make the type param match the registry type.

If you want such specific behavior (null if null, false if 0, true otherwise) then what would your generic method return if T is not a bool??

Maybe you can stop to use magic cast code. And cast explicitly, so you'll always got what you want.

Related

How to use C# generics to simplify access to WinRT settings?

In WinRT, settings are stored as objects which means that you end up doing a lot of casting to get back to the type you want. Since that seems to map onto one of the reasons why generics were added to C#, I've been trying to simplify my code so that I can do something like:
public string LastRunVersion
{
get
{
return GetLocalSettingsValue<String>("LastRunVersion", null);
}
set
{
SetLocalSettingsValue("LastRunVersion", value);
}
}
The problem I'm having is with the signature for SetLocalSettingsValue. I tried:
private T GetLocalSettingsValue<T>(string tag, T defaultValue) where T:Object
but Object isn't allowed because it isn't a valid constraint. I know that I only store booleans and strings, so I then tried:
private T GetLocalSettingsValue<T>(string tag, T defaultValue) where T:String, bool
but the compiler says that "A type used as a constraint must be an interface, a non-sealed class or a type parameter".
What do I need to do with the definition in order to allow me to use string and bool?
Thanks.
Implementing two different methods, as Sriram suggests, does seem like the simplest solution for the immediate concern. That said, your generic approach is viable, has precedent, and will make it much easier to extend the code in the future.
In fact, what you tried was nearly correct. The main thing is that you don't actually need a constraint at all. The method declaration is fine without it, and though you don't show the method body, as long as all you need to do is cast some object reference to the type T, that will work:
private T GetLocalSettingsValue<T>(string tag, T defaultValue)
{
object value;
// initialize/retrieve the value somehow
// Check for value present, return default if missing, cast otherwise
return value != null ? (T)value : defaultValue;
}
In fact, since you are passing a default value, type inference will allow you to omit the type parameter in some cases. For example:
public string LastRunVersion
{
get { return GetLocalSettingsValue("LastRunVersion", (string)null); }
}
If you had a non-null default value, the above would be more interesting. :) With the null value, you have to cast it to string just for the compiler to know what the correct type is, which is practically the same as just providing the type parameter. But if you were passing a string literal or the value of a string variable, the type would be clear and the name of the type would not need to be provided at all (not even as a cast).
More interesting is the bool scenario:
public string LastRunVersion
{
get { return GetLocalSettingsValue("SomeBooleanSetting", false); }
}
Here, the literal has a clear type, and so you don't need to provide the type name in any form.
Finally, note that C# does have the idea of default values for types. If you want to support non-null, non-zero default values, then your current approach is good. However, if your defaults are always going to be things like null, false, or 0 (e.g. for an int, should you ever need to store something like that), then you don't need the default parameter at all:
private T GetLocalSettingsValue<T>(string tag)
{
object value;
// initialize/retrieve the value somehow
// Check for value present, return default if missing, cast otherwise
return value != null ? (T)value : default(T);
}
Any reference type will use null as the default. For value types, you will get whatever the value would be if you created an instance using the parameterless constructor (all value types have a parameterless constructor). Numeric types all default to their version of 0, bool defaults to false, etc.
Naturally, in that case you will always have to provide the type parameter, since there aren't any arguments from which the type parameter could be inferred.

How to test a null value variable if it's a string?

Is it possible to test if a variable is defined as a string if the value inside it is null?
If I write:
string b = null;
bool c = b is string;
Then c will be false because is looks at the content, which is null and not a string.
If I write:
string b = null;
bool c = (b.GetType() == typeof(string));
Then it crashes because s is null and you can't call GetType() on a null value.
So, how can I check b to find out what type it is? Some kind of reflection maybe? Or is there any simpler way?
Edit 1: Clarification of the question!
I was a bit unclear in my question and that was my fault. In the example it looks like I'm trying to test the content of the variable. But I want to test the variable itself without looking at the content. In the code examples given I can see that b is a string, but what if I don't know if b is a string and just want to test the variable s to see if it is a string or not.
So, how can I know what type the variable is defined as? As in this example, but x is an unknown variable that might be defined as a string and it might be null as well (since it might be null this example won't work).
bool c = (x.GetType() == typeof(string));
Edit 2: The working solution!
Thanks to all the answers given I was able to solve it. This is how the working solution became. I first created a help function to test the defined type of a variable that works even if the value is null and it doesn't point to anything.
public static Type GetParameterType<T>(T destination)
{
return typeof(T);
}
Then I can just call this function and test my "suspected string" and find out if it really is a string or not.
// We define s as string just for this examples sake but in my "definition" we wouldn't be sure about whether s is a string or not.
string s = null;
// Now we want to test to see if s is a string
Type t = GetParameterType(s);
b = t == typeof(string); // Returns TRUE because s has the type of a string
b = t is string; // Returns FALSE because the content isn't a string
This is just what I wanted to find out!!! Thank you all for squeezing your brains...
You cannot check the type of null because null has no type. It doesn't reference anything at all, therefore there is nothing that C# can look at to find out the actual type.
(Everyone else seems to be answering the question "How can I tell if a string reference is null or empty - but I think the question is "how can I tell if the underlying type of a null reference is string...)
There might be a way to fiddle it though - you might be able to use a generic method as mentioned here:
.NET : How do you get the Type of a null object?
(That link was posted by someone else - not me - as a comment to your original post!)
So you want to know if there is a direct method to check of an object type whose value is set to NULL
In The simple word the answer is NO.
A null reference does not point to any Storage Location, so there is no metadata from which it can make that determination.
Although if you already know it is of type String , you can use following two functions for checking null values
String.IsNullOrWhiteSpace(stringObject);
and
String.IsNullOrEmpty(stringObject)
The best that you could do to set a value to unknown type is use
Convert.ChangeType
e.g. as given in .NET : How do you get the Type of a null object?
public void GetObjectValue<T>(out T destination)
{
object paramVal = "Blah.Blah.";
destination = default(T);
destination = Convert.ChangeType(paramVal, typeof(T).GetType());
}
The type of T can be inferred, so you shouldn't need to give a type parameter to the method explicitly.
Here it is
String.IsNullOrEmpty(s);
If you want to tell whether the actual value is a string, you can't do that with null, as null doesn't have a type.
So it seems you want to determine the actual type of the variable (the one it was declared as):
If the variable is of type string, then you know it at compile time (you declared it as string, after all).
If the variable is generic (like in generic types or a generic method), you can test it via typeof(T), assuming T is your type parameter.
If you got the variable as object though (e.g. as argument of a method), then there is no way to determine its original type if its value is null.
Use the String.IsNullOrEmpty method to check it.
string b = null;
bool c = String.IsNullOrEmpty(b);
See this MSDN link for further details.
IsNullOrWhiteSpace(variableName)
string.IsNullOrEmpty()
var.Trim().Length < 1
The third one is the one I personally use, as it is version-independent.

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# question on what this code means

I am learning c# code from one of the applications that I run SQL queries from.
I am wondering what the following code does in layman's terms:
return typeof(ViewModelBase<T>).GetProperty(propertyName) != null;
This is in a function that returns a boolean and a string is passed into it.
ViewModelBase<T> is an abstract class. Can someone also explain what the <T> does in this? I have ideas on these but I'm not sure what exactly is true.
Thanks!
The code returns true if the type has the property, and false if it doesn't.
This code will be written inside of a generic class, with a type parameter of T. In generics, each time a "hard" type is used with the generic class, the compiler creates a brand new concrete type. So for example, if there was code in your project that was using ViewModelBase<int>, ViewModelBase<string>, and ViewModelBase<MyType>, there would be three concrete types created in the final assembly by the compiler.
Each of these three hypothetical types would have properties and methods. The code shown above would (for all intents and purposes) be duplicated three times, with the type parameter "T" substituted with int, string and MyType in each of the three cases.
GetProperty() would then check to see if the concrete types had the property given in the "propertyName" variable, and return true or false accordingly.
That tells you whether or not the class type ViewModelBase<T>, based on the given type of T, has a public property with the same name as the value of propertyName.
Type.GetProperty() returns a PropertyInfo object if there's such a property; null otherwise. Hence the boolean comparison against null.
The code piece that you have there is part of a generic type, having a type argument T. Now, we don't see the full method, but I can imagine it looks something like so:
public static bool T HasProperty<T>(string propertyName)
{
return typeof(ViewModelBase<T>).GetProperty(propertyName) != null;
}
Let's say you have a class Customer:
class Customer
{
// implementation of class Customer goes here
}
Then you could call the HasProperty method like this:
bool itsThere = HasProperty<Customer>("SomePropertyName");
This means that the HasProperty method will return true if ViewModelBase<Customer> has a property called SomePropertyName, otherwise false.
This checks whether ViewModelBase<T> has a property with a name equal to propertyName.

Assert.AreEqual to not fail when comparing an enum and an int

I'm not sure if this is doable, but I will just give a shot.
I am calling Assert.AreEqual() method.
For the parameters, I'm passing...
an enum value which has Int32 as the underlying type because I didn't specify the base type
an int (Int32) value
Assert fails because it sees that the enum is not int (which is definitely correct).
However, is there a way to make this Assert pass when the enum has the correct int value as the 2nd parameter?
I can cast the enum to int and have it a quick fix, but it's really ugly.
I was expecting some kind of overriding a method that Assert uses to compare 2 different objects and implicitly make that enum type look like an int. However, I wasn't successful at finding any hint/answer around that so far.
Someone suggested to create a type converter and use the TypeConverterAttribute to get around. If this works for sure and is the only way to do it, I would; however, it does seem a lot of unnecessary work.
By calling Assert.AreEqual(enum, int), you are calling the Assert.AreEqual(object, object) method, as there is no overload that has an enum and an int as parameters.
I do not think that casting the enum to an int is ugly - in fact I think it is perfectly acceptable and a very common technique. If you were doing a normal equality comparison (ie. 1 == MyEnum.Value), you would get a compiler error as there is no implicit conversion, only an explicit one which requires a cast to work.
A type converter may work, but you need to ask yourself if doing that will actually give you any real benefit for the amount of effort involved. Personally, I would just leave the cast to an int.
If you are asserting something like the return value of a method call, why not just assert based on what value you expect?
MyEnum actual = SomeMethod();
Assert.AreEqual(MyEnum.Value, actual);
This does not require the cast as the two types are the same, and you are asserting the expected value.
I was expecting some kind of overriding a method that Assert uses to compare 2 different objects and implicitly make that enum type look like an int.
That won't work, since Assert.AreEqual is a static method, and you cannot override static methods, nor can you add overloads for static methods through extension methods.
Anyway, even if you could, you would violate the contract for Assert.AreEqual. You want to have Assert.AreEqual(myEnum.One, 1) yield true, although myEnum.One.Equals(1) as well as 1.Equals(myEnum.One) return false. That's inconsistent.
Casting to int is not ugly, it's the correct solution to your problem. After all, you want to check if the numerical value of the enum matches some integer. If that's what you want to check, write it down like this.

Categories

Resources