Is it possible to cast out param arguments in C#? I have:
Dictionary<string,object> dict; // but I know all values are strings
string key, value;
Roughly speaking (and if I didn't have static typing) I want to do:
dict.TryGetValue(key, out value);
but this obviously won't compile because it "cannot convert from 'out string' to 'out object'".
The workaround I'm using is:
object valueAsObject;
dict.TryGetValue(key, out valueAsObject);
value = (string) valueAsObject;
but that seems rather awkward.
Is there any kind of language feature to let me cast an out param in the method call, so it does this switcheroo for me? I can't figure out any syntax that'll help, and I can't seem to find anything with google.
I don't know if it is a great idea, but you could add a generic extension method:
static bool TryGetTypedValue<TKey, TValue, TActual>(
this IDictionary<TKey, TValue> data,
TKey key,
out TActual value) where TActual : TValue
{
if (data.TryGetValue(key, out TValue tmp))
{
value = (TActual)tmp;
return true;
}
value = default(TActual);
return false;
}
static void Main()
{
Dictionary<string,object> dict
= new Dictionary<string,object>();
dict.Add("abc","def");
string key = "abc", value;
dict.TryGetTypedValue(key, out value);
}
I spy with my little eye an old post that was still active a month ago...
Here's what you do:
public static class DictionaryExtensions
{
public static bool TryGetValueAs<Key, Value, ValueAs>(this IDictionary<Key, Value> dictionary, Key key, out ValueAs valueAs) where ValueAs : Value
{
if(dictionary.TryGetValue(key, out Value value))
{
valueAs = (ValueAs)value;
return true;
}
valueAs = default;
return false;
}
}
And because compilers are great, you can just call it like this:
dict.TryGetValueAs(key, out bool valueAs); // All generic types are filled in implicitely! :D
But say you're not creating a blackboard AI and just need to call this operation the one time. You can simply do a quicksedoodle inliner like this:
var valueAs = dict.TryGetValue(key, out var value) ? (bool)value : default;
I know these answers have been given already, but they must be pretty old because there is no cool hip modern inlining going on to condense these methods to the size we really want: no more than 1 line.
I used Marc's extension method but added a bit to it.
My problem with the original was that in some cases my dictionary would contain an int64 whereas I would expect an int 32. In other cases the dictionary would contain a string (for example "42") while I would like to get it as an int.
There is no way to handle conversion in Marc's method so I added the ability to pass in a delegate to a conversion method:
internal static bool TryGetTypedValue<TKey, TValue, TActual>(
this IDictionary<TKey, TValue> data,
TKey key,
out TActual value, Func<TValue, TActual> converter = null) where TActual : TValue
{
TValue tmp;
if (data.TryGetValue(key, out tmp))
{
if (converter != null)
{
value = converter(tmp);
return true;
}
if (tmp is TActual)
{
value = (TActual) tmp;
return true;
}
value = default(TActual);
return false;
}
value = default(TActual);
return false;
}
Which you can call like this:
int limit;
myParameters.TryGetTypedValue("limitValue", out limit, Convert.ToInt32)
No, there is no way around that. The out parameter must have a variable that matches exactly.
Using a string reference is not safe, as the dictionary can contain other things than strings. However if you had a dictionary of strings and tried to use an object variable in the TryGetValue call, that won't work either even though that would be safe. The variable type has to match exactly.
If you know all values are strings use Dictionary<string, string> instead. The out parameter type is set by the type of the second generic type parameter. Since yours is currently object, it will return an object when retrieving from the dictionary. If you change it to string, it will return strings.
No, you can't. The code inside the method is directly modifying the variable passed to it, it is not passed a copy of the content of the variable.
It is possible by using the Unsafe.As<TFrom, TTo>(ref TFrom source) method to do the cast inline.
var dict = new Dictionary<string, int>
{
["one"] = 1,
["two"] = 2,
["three"] = 3,
};
long result = 0;
dict.TryGetValue("two", out Unsafe.As<long, int>(ref result));
Depending on which platform you are on, this may require you to add a reference to System.Runtime.CompilerServices.Unsafe.
Related
Part of my software is using reflection. The issue I am having is that while I can get the type of the property, I cannot convert the string value using the Type from the PropertyInfo. This is the reason why i am using t in the sample code.
The below code demonstrates the issue with the error message as a code comment. The syntax error is on the t. how can I fix this problem? thanks
class Program
{
static void Main(string[] args)
{
Type t = typeof(Letters);
Letters letter = "A".ToEnum<t>(); //-- Type or namespace expected.
}
}
public enum Letters { A, B, C }
//-- This is a copy of the EmunHelper functions from our tools library.
public static class EnumExt
{
public static T ToEnum<T>(this string #string)
{
int tryInt;
if (Int32.TryParse(#string, out tryInt)) return tryInt.ToEnum<T>();
return (T)Enum.Parse(typeof(T), #string);
}
public static T ToEnum<T>(this int #int)
{
return (T)Enum.ToObject(typeof(T), #int);
}
}
Solution:
The following works because when the value is set using reflection, the actual type of Enum is accepted. Where myObject.Letter = result is not.
Type t = currentProperty.PropertyType;
Enum result = Enum.Parse(t, #string) as Enum;
ReflectionHelper.SetProperty(entity, "LetterPropertyName", result);
Thank you all for your help.
Enum.Parse(t, #string) as Enum;
That accomplishes the same thing as the solution you posted.
To be able to call a generic method, the type must be known at compile time. Your use is invalid syntax.
To be able to call your method, you'll have to use reflection to get a reference to the correct generic function so you may call it.
public static object ToEnum(this string s, Type type)
{
var eeType = typeof(EnumExt);
var method = eeType.GetMethod("ToEnum", new[] { typeof(string) })
.MakeGenericMethod(type);
return method.Invoke(null, new[] { s });
}
Then you could call it:
Letters letter = (Letters)"A".ToEnum(t);
p.s., I strongly urge you to change your variable names to something else. Just because you can name your variables as keywords, doesn't mean that you should.
I'm not an expert with reflection, but this works:
static void Main(string[] args)
{
Type t = typeof(Letters);
MethodInfo info = typeof(EnumExt).GetMethod("ToEnum", new Type[] { typeof(string) });
var method = info.MakeGenericMethod(new Type[] { t });
var result = (Letters)method.Invoke(null, new [] { "A" });
Console.ReadLine();
}
I think your question can be understood in two ways:
i) you want to fix a syntax error
ii) you need a working implementation for the function you provide
For i), I would suggest you to change:
Letters letter = "A".ToEnum<t>()
into
Letters letter = "A".ToEnum<Letters>()
because generics are solved at compile time, hence you cannot use variables as parameters.
For ii), you may change the way you provide the type argument, from "generic" argument to "normal" argument (as proposed by Jeff Mercado). By doing so the prototype of your function becomes:
public static T ToEnum(this string #string, Type t)
I conclude with two remarks:
reflection is VERY slow to my experience. I once wrote an assembly parser making extensive use of reflection on enums for register names. It used to run for minutes (which used to make VS debugger complain about non-responsiveness) when an equivalent version without any reflection used to execute in less than 10 seconds.
as Jeff Mercado pointed out, I cannot see any good reason for you to use the same vocable for type names and variable names
From my question # Possible to make a method with random type? I got this:
public static T GetParameterValue<T>(Parameter source)
{
return (T)source.Value;
}
Now I wonder if it Is also possible to change it in any way so I can set T to the Parameter.Type?
So GetParameterValue(ABoolParameter) where ABoolParameter.Type = bool, ABoolParameter.Value=true
and have it return as a bool with it's value set to true?
and for a string:
GetParameterValue(AStringParameter) where AStringParameter.Type = string, AStringParameter.Value = "somestring"
and have it return as a string with it's value set to "somestring"?
So it should return a bool without me declaring T as a bool before?
Not sure you can do that. And even if you can, it may be a bit confusing for other (more novice) developers to read/maintain the code.
Alternatively, you can use dynamic (or even plain ol' object).
Are you thinking this?
public static void SetParameterValue<T>(this Parameter param, T value)
{
param.Value = value;
param.Type = typeof(T);
}
It depends on what Type on Parameter is. You could create a bunch of if / else statements if it isn't an actual System.Type, but it might not be the most readable thing to do.
I want to check that some integer type belongs to (an) enumeration member.
For Example,
public enum Enum1
{
member1 = 4,
member2 = 5,
member3 = 9,
member4 = 0
}
Enum1 e1 = (Enum1)4 gives me member1
Enum1 e2 = (Enum1)10 gives me nothing and I want to check it.
Use Enum.IsDefined
Enum.IsDefined(typeof(Enum1), 4) == true
but
Enum.IsDefined(typeof(Enum1), 1) == false
As Sam says, you can use IsDefined. This is somewhat awkward though. You may want to look at my Unconstrained Melody library which would let you us:
Enum1 e2 = (Enum1)10;
if (e2.IsNamedValue()) // Will return false
{
}
It's probably not worth it for a single enum call, but if you're doing a lot of stuff with enums you may find some useful things in there.
It should be quicker than Enum.IsDefined btw. It only does a linear scan at the moment, but let me know if you need that to be improved :) (Most enums are small enough that they probably wouldn't benefit from a HashSet, but we could do a binary search...)
int testNum = 5;
bool isMember = Enum.GetValues(typeof(Enum1)).Cast<int>().Any(x => x == testNum);
You look through the values of the enum and compare them to the integer.
static bool EnumTest(int testVal, Enum e)
{
bool result = false;
foreach (var val in Enum.GetValues(typeof(Enum1)))
{
if ((int)val == testVal)
{
result = true;
break;
}
}
return result;
}
Edit: Looks like Sam has a better solution.
You can use Enum.GetValues to get all defined values. Then check if your value exists in that list.
http://msdn.microsoft.com/en-us/library/system.enum.getvalues.aspx
Be careful this won't work if you have an enum for 3 (Apples and Pears) the methods above won't detect it as valid.
[Flags]
public enum Fruit
{
Apples=1,
Pears=2,
Oranges =4,
}
Here's a succinct little snippet from an extension method I wrote a few years ago. Combines TryParse with IsDefined to do it all in one swoop and handle values that don't exist in the enum.
if (value != null)
{
TEnum result;
if (Enum.TryParse(value.ToString(), true, out result))
{
// since an out-of-range int can be cast to TEnum, double-check that result is valid
if (Enum.IsDefined(typeof(TEnum), result.ToString() ?? string.Empty))
{
return result;
}
}
}
Here's the extension for integer values
public static TEnum ParseToEnum<TEnum>(this int value, TEnum? defaultValue = null, bool useEnumDefault = false) where TEnum : struct
{
return ParseToEnumInternal(value, defaultValue, useEnumDefault);
}
And a usage
public enum Test
{
Value1 = 1,
Value2 = 3
}
var intValue = 1;
var enumParsed = intValue.ParseToEnum<Test>(); // converts to Test.Value1
intValue = 2;
enumParsed = intValue.ParseToEnum<Test>(); // either throws or converts to supplied default
enumParsed = 3.ParseToEnum<Test>(); // converts to Test.Value2
Some people don't like how it dangles off the end of the (potentially nullable) value, but I have an extension that handles null values of nullable types (int?) and I like it myself, so ...
I can post like a Gist of the whole extension method with all the overloads if you're interested.
Use:
if (Enum.IsDefined(typeof(Fruit),e2))
{
//Valid Value
}
else
{
//Invalid ENum Value
}
Found this useful. https://stackoverflow.com/a/64374930/16803533
no need to use IsDefined and No range checking
I am working on a tool where I need to convert string values to their proper object types. E.g. convert a string like "2008-11-20T16:33:21Z" to a DateTime value. Numeric values like "42" and "42.42" must be converted to an Int32 value and a Double value respectively.
What is the best and most efficient approach to detect if a string is an integer or a number? Are Int32.TryParse or Double.TryParse the way to go?
Int.TryParse and Double.TryParse have the benefit of actually returning the number.
Something like Regex.IsMatch("^\d+$") has the drawback that you still have to parse the string again to get the value out.
In terms of efficiency, yes, TryParse is generally the preferred route.
If you can know (for example, by reflection) the target type in advance - but don't want to have to use a big switch block, you might be interested in using TypeConverter - for example:
DateTime foo = new DateTime(2008, 11, 20);
TypeConverter converter = TypeDescriptor.GetConverter(foo);
string s = converter.ConvertToInvariantString(foo);
object val = converter.ConvertFromInvariantString(s);
I would recommend the .TryParse() personally. That's what I use anyhow. That's if your data is going to be wrong now and again. If you're certain the incoming strings will be able to convert to integers or doubles without a hitch, the .Parse() is faster.
Here's an interesting link to support this.
Keeping the idea of a converter to skip a switch block, you could use the concept of Duck Typing. Basically, you want to turn a string to X, so you make a method that will call X.TryParse(string, out X x) if X has TryParse on it, otherwise you just don't bother (Or I suppose you could throw an error). How would you do this? Reflection and Generics.
Basically you would have a method that would take in a type and use reflection to see if it has TryParse on it. If you find such a method you then call it and return whatever TryParse managed to get. This works well with just about any value type like say Decimal or DateTime.
public static class ConvertFromString
{
public static T? ConvertTo<T>(this String numberToConvert) where T : struct
{
T? returnValue = null;
MethodInfo neededInfo = GetCorrectMethodInfo(typeof(T));
if (neededInfo != null && !numberToConvert.IsNullOrEmpty())
{
T output = default(T);
object[] paramsArray = new object[2] { numberToConvert, output };
returnValue = new T();
object returnedValue = neededInfo.Invoke(returnValue.Value, paramsArray);
if (returnedValue is Boolean && (Boolean)returnedValue)
{
returnValue = (T)paramsArray[1];
}
else
{
returnValue = null;
}
}
return returnValue;
}
}
Where GetCorrectMethodInfo would look something like this:
private static MethodInfo GetCorrectMethodInfo(Type typeToCheck)
{
MethodInfo returnValue = someCache.Get(typeToCheck.FullName);
if(returnValue == null)
{
Type[] paramTypes = new Type[2] { typeof(string), typeToCheck.MakeByRefType() };
returnValue = typeToCheck.GetMethod("TryParse", paramTypes);
if (returnValue != null)
{
CurrentCache.Add(typeToCheck.FullName, returnValue);
}
}
return returnValue;
}
And use would be:
decimal? converted = someString.ConvertTo<decimal>();
I hate plugging myself, but I have this fully explained here:
GetCorrectMethodInfo
Rest of It
I just recently noticed Dictionary.TryGetValue(TKey key, out TValue value) and was curious as to which is the better approach to retrieving a value from the Dictionary.
I've traditionally done:
if (myDict.Contains(someKey))
someVal = myDict[someKey];
...
unless I know it has to be in there.
Is it better to just do:
if (myDict.TryGetValue(somekey, out someVal)
...
Which is the better practice? Is one faster than the other? I would imagine that the Try version would be slower as its 'swallowing' a try/catch inside itself and using that as logic, no?
TryGetValue is slightly faster, because FindEntry will only be called once.
How much faster? It depends on the
dataset at hand. When you call the
Contains method, Dictionary does an
internal search to find its index. If
it returns true, you need another
index search to get the actual value.
When you use TryGetValue, it searches
only once for the index and if found,
it assigns the value to your variable.
FYI: It's not actually catching an error.
It's calling:
public bool TryGetValue(TKey key, out TValue value)
{
int index = this.FindEntry(key);
if (index >= 0)
{
value = this.entries[index].value;
return true;
}
value = default(TValue);
return false;
}
ContainsKey is this:
public bool ContainsKey(TKey key)
{
return (this.FindEntry(key) >= 0);
}
Well in fact TryGetValue is faster. How much faster? It depends on the dataset at hand. When you call the Contains method, Dictionary does an internal search to find its index. If it returns true, you need another index search to get the actual value. When you use TryGetValue, it searches only once for the index and if found, it assigns the value to your variable.
Edit:
Ok, I understand your confusion so let me elaborate:
Case 1:
if (myDict.Contains(someKey))
someVal = myDict[someKey];
In this case there are 2 calls to FindEntry, one to check if the key exists and one to retrieve it
Case 2:
myDict.TryGetValue(somekey, out someVal)
In this case there is only one call to FindKey because the resulting index is kept for the actual retrieval in the same method.
I imagine that trygetvalue is doing something more like:
if(myDict.ReallyOptimisedVersionofContains(someKey))
{
someVal = myDict[someKey];
return true;
}
return false;
So hopefully no try/catch anywhere.
I think it is just a method of convenience really. I generally use it as it saves a line of code or two.
public bool TryGetValue(TKey key, out TValue value)
{
int index = this.FindEntry(key);
if (index >= 0)
{
value = this.entries[index].value;
return true;
}
value = default(TValue);
return false;
}
public bool ContainsKey(TKey key)
{
return (this.FindEntry(key) >= 0);
}
Like you can see TryGetValue is same as ContainsKey + one array lookup.
If your logic is only to check if the key is existing in the Dictionary and nothing else related to this key (taking the value for the key) you should use ContainsKey.
Try also checking this similar question: is-there-a-reason-why-one-should-use-containskey-over-trygetvalue