I have a txt file where from I can extract two strings (type and value). But, I need to cast it to the correct type. See the code bellow.
string type;
string value;
//example 1 //from the txt file
type = "int";
value = "25";
//example 2
type = "double";
value = "1.3";
//example 3
type = "string";
value = "blablabla";
//conversion I would like to do:
dynamic finalResult = (type)element.Value; //this returns an error
I need to do something like this, but I don't know to create a object type from the content of the string.
I tried to declare a Type:
Type myType = type;
But I dont know how to do it correctly.
In the name of clarity and type safety I think you should just use a combination of a switch expression and the various .TryParse() methods, having it return a generic type
static T? ReadVariable<T>(string type, string value) =>
type switch
{
"int" => int.TryParse(value, out int val) ? val : null, //null or throw an ex
"double" => double.TryParse(value, out double val) ? val : null,
"string" => string.TryParse(value, out string val) ? val : null,
"bool" => bool.TryParse(value, out bool val) ? val : null,
//... etc
_ => throw new NotSupportedException("This type is currently not supported")
};
int? num = ReadVariable<int>("int", "99"); //nullable return
//nullable handling
int num = ReadVariable<int>("int", "99") ?? default(int); //int type's default value is 0
int num = ReadVariable<int>("int", "99").GetValueOrDefault(-1); //default to an int value of your choice
Are you really going to have a situation where you need to parse out any type under the sun? This method allows you to maintain full control over what happens. Use of dynamic may potentially be way more headache than you expect
Update: thanks to #ckuri for pointing out that you may also want to use the try parse overload that allows for invariant culture in order to account for international numbering schemes
Update 2: added an examples of nullable handling
does this work?
object result;
string value = "some value";
string type = "some type";
switch(type)
{
case "int":
result = Convert.ToInt32(value);
break;
case "double":
result = Convert.ToDouble(value);
break;
case "string":
result = value;
break;
// case "any other datatype":
// result = convert explicitly to that datatype
}
Related
Can someone please explain the following behaviour?
I am trying to return null, as int?, if a int.TryParse return false.
From the following options, all return null except the second:
var resultInt1 = int.TryParse(null, out var result) ? result : (int?)default; //null
var resultInt2 = int.TryParse(null, out var result2) ? result2 : default; //0
var resultInt3 = int.TryParse(null, out var result3) ? result3 : (int?)null; //null
var resultInt4 = int.TryParse(null, out var result4) ? result4 : default(int?); //null
isn't default for int? null? Why is it returning 0?
The conditional operator always has to select a best type from the types of the two possible results. In 3 of your samples, you're asking it to select between int and int? and it decides that int? is the best type.
However, when you have just int and default, default doesn't have a type and must be inferred from context. So the only possible type the compiler can choose as the type for the conditional is int. Having made that decision, it now knows that default is the same as default(int) which is 0.
If the string to parse is null, Int32.TryParse will always return false, after setting the default value for the out parameter.
So you get always the false part of your expressions but all the out variables above are set to their default value.
Because Int32.TryParse expects the out variable to be an integer, then, if you look at the value set in the out variables you will see that are all set to 0.
You can see this behavior looking at the referencesource site following the source code of Int32.TryParse
In the second case the type is int, not int?.
int.TryParse works with int not int? so it's the else part that dictates int? in the 1st, 3rd and 4th cases.
It becomes clearer if you 'unwind' the code.
//var resultInt1 = int.TryParse(null, out var result) ? result : (int?)default; //null
int result; // <--- int, not 'int?'
int? resultInt1; // has to be nullable
if (int.TryParse(null, out result))
resultInt1 = result;
else
resultInt1 = (int?)default; //null
// var resultInt2 = int.TryParse(null, out var result2) ? result2 : default; //0
// is equivalent (note 'int', not 'int?'
// int resultInt2 = int.TryParse(null, out var result2) ? result2 : default; //0
// is equivalent
int result2; // <--- int, not 'int?'
int resultInt2; // <------------------- here, it's an int
if (int.TryParse(null, out result2))
resultInt2 = result2;
else
resultInt2 = default; <--‐------ the only case with an 'int', not an 'int?'
I have a string number in my C# program, it's "6.967.015". That's the german number format where "." seperates the 1000-groups and "," is the decimal seperator.
I made a function that uses Double.TryParse to convert the text to a double value. It works fine:
if (Double.TryParse(text, out result))
{
return result;
}
else
{
return defaultValue;
}
Now I needed a second type to be convertable and instead of copying the function, I wanted to make a function that accepts the type (don't mind the Type argument instead of generic <T> function, it's for integrity reasons).
public static object DefaultIfNotValid(this object value, Type type, object defaultValue)
{
var converter = TypeDescriptor.GetConverter(type);
object convertedValue;
if (converter != null)
{
try
{
convertedValue = converter.ConvertFrom(value);
return convertedValue;
}
catch (Exception)
{
return defaultValue;
}
}
return defaultValue;
}
The problem with this code is that it works for "123" but it doesn't work for the above number "6.967.015". The Convert function throws "6.967.015 is not a valid value for double". I tried giving the function a culture parameter to see if that was the problem, but that didn't work either (I passed null for the TypeDescriptorContext).
converter.ConvertFrom(null, new CultureInfo("de-de"), value);
That still threw the same exception. I also tried a custom culture with explicitly set group and decimal seperator, but still the same issue.
Maybe it's not even the culture but something else that the converter doesn't like about the value.
Does anyone know what could be the cause of this? Even though the string converts just fine with an explicit double.TryParse call.
You can try like this:
var nf = new NumberFormatInfo{NumberDecimalSeparator = ",", NumberGroupSeparator = "."};
var convertedValue = Convert.ToDouble(value, nf);
If TryParse method works use "method overload", default value for failed converting will be target type indicator in your case
Create own converting method for every type you want to convert
public static double DefaultIfNotValid(this string value, double defaultValue)
{
double temp = 0;
if (double.TryParse(value, out temp) == true)
return temp;
return defaultValue;
}
public static int DefaultIfNotValid(this string value, int defaultValue)
{
int temp = 0;
if (int.TryParse(value, out temp) == true)
return temp;
return defaultValue;
}
Then using seems not so painful
string rawValue = "6.967.015";
double defaultValue = 9.9;
double parsedValue = rawValue.DefaultIfNotValid(defaultValue);
In c# a value-type cannot have a value of null, however you can enable this by appending a question mark.
e.g.
int intCannotBeNull = 1;
int? intCanBeNull = null;
Additionally, in C# many value types have static members so you can do this for example:
string strValue = "123";
intCannotBeNull = int.Parse(strValue);
However you can't do either of these:
intCanBeNull = int?.Parse(strValue);
intCanBeNull = (int?).Parse(strValue);
C# gets confused. Is there a valid syntax that means strValue could be null or a valid integer value and have the assignment work?
I know there are easy workarounds, for example:
intCanBeNull = (strValue == null) ? null : (int?)int.Parse(strValue);
and other variants of the same thing but that's just messy...
int? is syntactic sugar for Nullable<int>. You are asking about Nullable<int>.Parse. There is no such method. That is where your confusion lies.
Parse will not handle null values, It will throw exception. You have to use either TryParse or Convert class to parse
Convert.ToInt32(int or int?)
This applies for long, float, decimal etc..
int? is in fact Nullable<int>. That Nullable<T> struct doesn't have the methods of the T class. Hence, you have to do it yourself.
In the case of int?, you could try something like this:
string s = "1";
int? result;
if (string.IsNullOrEmpty(s))
{
result = null;
}
else
{
int o; // just a temp variable for the `TryParse` call
if (int.TryParse(s, out o))
{
result = o;
}
else
{
result = null;
}
}
// use result
I wanted to create a function, which will check the value of the parameter, if it's null it should set the value based on type of the parameter, else it should just return the value as it is.Here what i have tried.
public static T ConvertNull<T>(T obj)
{
if (String.IsNullOrEmpty(obj.ToString()))
{
HttpContext.Current.Response.Write("COMING IN");
if (typeof(T) == typeof(Int32))
{
return (T)Convert.ChangeType(0, typeof(T));
}
else if (typeof(T) == typeof(DateTime))
{
return (T)Convert.ChangeType(DateTime.Now, typeof(T));
}
else
{
return (T)Convert.ChangeType(String.Empty, typeof(T));
}
}
else
{
HttpContext.Current.Response.Write("ELSE");
return obj;
}
}
But the problem is it always goes in ELSE section and returns Junk value.
Can anyone tell me what's wrong with the above function.
String.IsNullOrEmpty(obj.ToString()) is very rarely going to be true. THe only thing I can think of that will generate an empty string vi ToString() is another empty string. In fact unless ToString() has been overridden (like it has been for native types like DateTime and int, you will get the fully qualified name of the object.
maybe you want
if (obj == default(T))
?
If you have a nullable type that you want to replace with some value in the event that it is null, and return the existing value in the event that it is not-null, there is alerady an existing operator that does this, the ?? operator:
int? i = null; //note of course that a non-nullable int cannot be null
int n = i ?? 0; //equals zero
string s = null;
string s2 = s ?? ""; //equals an empty string
string s3 = "hi";
string s4 = s3 ?? ""; //equals "hi"
Conveniently the ?? operator will not even compile in the event that the first operand's type is not nullable.
Basically I want to be able to have one function that takes in a Nullable Type and then returns the value if it has one or the string value "NULL" if it's null so the function needs to be able to take in any nullable type and then return that type or return the string NULL. Below is kind of what I'm looking for as an example I just can't seem to figure out what I need to do as far as my function.
UInt16? a = 5;
UInt16? b = null;
UInt32? c = 10;
UInt32? d = null;
Console.WriteLine(MyFunction<UInt16?>(a)) // Writes 5 as UInt16?
Console.WriteLine(MyFunction(UInt16?>(b)) // Writes NULL as String
Console.WriteLine(MyFunction(UInt32?>(c)) // Writes 10 as UInt32?
Console.WriteLine(MyFunction(UInt32?>(d)) // Writes NULL as String
static T MyFunction<T>(T arg)
{
String strNULL = "NULL";
if (arg.HasValue)
return arg;
else
return strNULL;
}
static string MyFunction<T>(Nullable<T> arg) where T : struct
{
String strNULL = "NULL";
if (arg.HasValue)
return arg.Value.ToString();
else
return strNULL;
}