The object Row is a class, that has a property Values which is a Dictionary.
Below are extension methods on the Values property.
public static T TryGetValue<T>(this Row row, string key)
{
return TryGetValue(row, key, default(T));
}
public static T TryGetValue<T>(this Row row, string key, T defaultValue)
{
object objValue;
if (row.Values.TryGetValue(key, out objValue))
{
return (T)objValue;
}
return defaultValue;
}
If I do:
user.Username = user.Values.TryGetValue<string>("Username");
This happends if the key "username" is not in the Dictionary.
I get an exception, invalid cast:
The following error ocurred:
System.InvalidCastException: Specified cast is not valid.
TryGetValue[T](Row row, String key, T defaultValue)
TryGetValue[T](Row row, String key)
So I guess TryGetValue doesn't work on strings?
Is it possible you've got an entry in your dictionary with key "Username" whose value is not a string?
I've added comments to your method explaining how this could lead to your issue.
// I'm going to go ahead and assume your Values property
// is a Dictionary<string, object>
public static T TryGetValue<T>(this Row row, string key, T defaultValue)
{
// objValue is declared as object, which is fine
object objValue;
// this is legal, since Values is a Dictionary<string, object>;
// however, if TryGetValue returns true, it does not follow
// that the value retrieved is necessarily of type T (string) --
// it could be any object, including null
if (row.Values.TryGetValue(key, out objValue))
{
// e.g., suppose row.Values contains the following key/value pair:
// "Username", 10
//
// then what you are attempting here is (string)int,
// which throws an InvalidCastException
return (T)objValue;
}
return defaultValue;
}
It should work fine, either if the key "Username" is in the dictionary with a corresponding string value, or not in the dictionary at all.
The fact that you're getting an InvalidCastException shows that the value for the "Username" key wasn't a string.
Related
I am trying to implement a dictionary in such a way that It will only add in a certain value to a key if that new value is greater than the currently existing value
So the basic scenarios would be:
If the key is not available, it will create a new key and a value
If the key if available, it will check if the current value is greater than the value that is already assigned to that key and will only update if it is greater.
Before I explain the problem I am facing here is my code
static IDictionary<string, string> versionStack = new Dictionary<string, string>();
foreach(var item in RequiredApps)
{
nameOfApp = item.Key;
minimumVersionOfApp = item.Value.minVersion;
if (versionStack.TryGetValue(nameOfApp, out minimumVersionOfApp))
{
if (Convert.ToInt32(minimumVersionOfApp) >= Convert.ToInt32(item.Value.minVersion))
minimumVersionOfApp = item.Value.minVersion;
}
versionStack[nameOfApp] = minimumVersionOfApp;
}
Note: Kindly do not worry about the for loop as it works fine and gives no problem there. Just want to display only the specific code that gives me problem
Right now I have been able to fulfill the functionality to a certain level but the problem is when the TryGetValue is executed it turns all my values to null.
I am using the TryGetValue to see if a key has a value and if so to retrieve it.
I am stuck here right now and would appreciate if anyone can help show me what I am doing wrong.
Edit :-
Given that the problem I am facing is quite unclear and as suggested by Rufus L I am adding a sample dummy application with exactly the problem I am facing
Hope this helps to clear any confusion :)
class Program
{
static IDictionary<string, string> versionStack = new Dictionary<string, string>();
static string appName;
static string minVersion;
static void Main(string[] args)
{
AddOnce();
AddTwice();
}
public static void AddOnce()
{
appName = "app01";
minVersion = "1.0";
versionStack.Add(appName, minVersion);
}
public static void AddTwice()
{
string existingValue;
appName = "app01";
minVersion = "3.0";
if (!versionStack.TryGetValue("app01", out existingValue) || Convert.ToInt32(existingValue) < Convert.ToInt32(minVersion))
{
versionStack[appName] = minVersion;
}
}
}
Based on the code you've shown, it looks like the problem is that you're using minimumVersionOfApp as the out parameter to the TryGetValue method, which will be set to null if TryGetValue fails, but then we're using it anyway.
Remember that the contract with any out parameter is that the method must assign a value to it before it returns. Typically (and specifically in this case), if TryGetValue returns false, then the out parameter is set to the default value for the type, which is null for classes.
Then, after the first if statement, you are assigning the value to the key even when TryGetValue returns false, which is likely why you're getting null values.
Instead, only use the out parameter if TryGetValue succeeds.
Here's a sample code that does this:
foreach(var item in RequiredApps)
{
var appName = item.Key;
string existingValue; // Note that this should be the same type as item.Value
// If the key doesn't exist (the first condition),
// or it does exist and our value is greater than the existing one (second condition)
// then update the key with our new value
if (!dependentModuleStack.TryGetValue(appName, out existingValue) ||
Convert.ToInt32(existingValue) < Convert.ToInt32(item.Value.minVersion))
{
versionStack[appName] = item.Value.minVersion;
}
}
It looks like your issue is not with Dictionary.TryGetValue, but Convert.ToInt32
The version number is a double, and not an integer. you should use the Convert.ToDouble instead of Convert.ToInt32
if (!versionStack.TryGetValue("app01", out existingValue) || Convert.ToDouble(existingValue) < Convert.ToDouble(minVersion))
{
versionStack[appName] = minVersion;
}
I am trying to extend the Field method of the DataRow extension to add a parameter to check if the column exists:
public static T? FieldValue<T>(
this DataRow row,
string columnName,
bool checkColumn = false) where T : struct
{
return
checkColumn
&& !row.Table.Columns.Contains(
columnName)
? default(T)
: row.Field<T>(
columnName);
}
This works fine for int, datetime etc. However, when I try to use it with string it shows error:
The type string must be non-nullable
I am also getting error if there is a null value in the database:
Cannot cast DBNull.Value to type 'System.Decimal'
Is there a way it can be extended the Dataextension seamlessly?
As Markus pointed out, you've got two challenges here. One is about structs vs value types and the other one is to do with the fact that you have to deal with null values.
The second one is trivial to tackle: Just add a ? to your implementation like this: row.Field<T?>(columnName) and your exceptions will be gone.
The first problem, however, is a nasty and frequently encountered one. I am unaware of a pretty way of solving this. Let me still suggest something:
Based on your code above I assume that you are happy to get back Nullable types even for non-nullable columns. So here is something you could do to support reference types on top of what you have and still avoid too much code duplication:
// value type version
public static T? FieldValueStruct<T>(this DataRow row, string columnName, bool checkColumn = false)
where T : struct
{
return row.GetValue(columnName, checkColumn, default(T), row.Field<T? /*with a question mark!!!*/ >);
}
// reference type version
public static T FieldValueClass<T>(this DataRow row, string columnName, bool checkColumn = false)
where T : class
{
return row.GetValue(columnName, checkColumn, default(T), row.Field<T>);
}
// shared amongst value and reference type implementation
private static T GetValue<T>(this DataRow row, string columnName, bool checkColumn, T defaultValue, Func<string, T> getter)
{
return checkColumn && !row.Table.Columns.Contains(columnName)
? defaultValue
: getter(columnName);
}
With this code in place, you get the functionality you want but at a price: You will need to specify type parameters (just like you do now) when you call these methods because type inference won't work (here is why).
string s;
// no type inference, type parameter must be specified
s = row.FieldValueClass<string>("test");
Also, you will need to differentiate in your calls between the value type version and the reference type version which simply isn't pretty. Why do we need to use two different names for the methods? The reason for that is that you cannot overload methods by simply adding different type constraints (see here).
The type inference topic could be solved by using an out parameter which, however, comes again with a bunch of downsides...
// value type version that works with type inference
public static void FieldValueStruct<T>(this DataRow row, string columnName, out T? value, bool checkColumn = false)
where T : struct
{
value = row.GetValue(columnName, checkColumn, default(T), row.Field<T?>);
}
// reference type version that works with type inference
public static void FieldValueClass<T>(this DataRow row, string columnName, out T value, bool checkColumn = false)
where T : class
{
value = row.GetValue(columnName, checkColumn, default(T), row.Field<T>);
}
Now, you can call your method without the type parameter like this:
string s;
// with type inference, doesn't work with properties, though, only with fields
row.FieldValueClass("test", out s);
Unfortunately, this does not work with properties - only with fields.
You see, the world is evil and, sometimes, we cannot do too much about it. ;)
Update based on your comment:
The code below changes your semantics a little but perhaps that's ok:
public static T FieldValue<T>(this DataRow row, string columnName, bool checkColumn = false)
{
return checkColumn && !row.Table.Columns.Contains(columnName)
? default(T)
: row.Field<T>(columnName);
}
Calling this method would need to look like:
// this will return 0 if the column is not available, a null value from the database will cause an exception
int i = r.FieldValue<int>("test");
// this will return null if the column is not available, a null value from the database would be ok
int? iNullable = r.FieldValue<int?>("test");
// this will return null if the column is not available, a null value from the database would be ok
string s = r.FieldValue<string>("test");
The reason for the first error message is the where-constraint:
where T : struct
This constraint requires that each type T that is used as a type parameter is a value type. string is a reference type, hence the error message. In order tomsolve the problem, you should remove the constraint if you don't need it.
As regards the Null-value problem, you should check whether the column is null (if it exists) and in this case also return default(T). You can use the DataRow.IsNull method to check whether the cell is null.
I have the method
HandleNotification(string message, Dictionary<string, object> additionalData, bool isActive)
and I would take the from additionalData the value.
I have this additional data:
Extracoins:4
I don't understand how I can take the value 4 from additionalData for a specific key Extracoins.
You can get a value from a Dictionary like this if your only interested in accessing one specific key.
object value = null;
additionalData.TryGetValue("Extracoins", out value);
That way object will be the value in the Dictionary or it will remain null if the value is not found.
Or you can do:
if (additionalData.ContainsKey("Extracoins"))
{
object value = additionalData["Extracoins"];
}
Finally if you wanted to iterate over all the values in the Dictionary until you get the correct value you could do:
object value = null;
foreach (KeyValuePair<string, object> pair in additionalData)
{
if (pair.Key == "Extracoins")
{
value = pair.Value;
}
}
In my desktop C# application I start with a dictionary. I want to be able to check this dictionary for a key. If the dictionary has this key, I would like to pass it on to a method. If the dictionary doesn't have this key, I would like to create a blank list and just pass that on instead. How can I do this?
I get the error "given key was not present in the dictionary". Can I add a default so it is never null maybe?
// myDic was declared as a Dictionary<string, List<string>
// Here is how I call someFunction
string text = SomeFunction(stringValue1, stringValue2, myDic[field1.field2]);
// SomeFunction looks like this
string SomeFunction (string string1, string string2, List<string> ra)
{
// method
return stringResult;
}
Updated based on comments. To pass one key that may or may not exist you may do this(assuming the value is a List):
// assuming the method we are calling is defined like this:
// public String SomeFunction(string string1, String string2, List<String> ra)
List<string> valueToPassOn;
if (_ra.ContainsKey(lc.Lc))
{
valueToPassOn = _ra[lc.Lc]
}
else
{
valueToPassOn = new List<string>();
}
string text = tooltip.SomeFunction(something1, something2, valueToPassOn);
Should you want to pass an entire dictionary (as the question originally read), regardless of whether or not the dictionary exists:
You have two options. Either create the dictionary regardless like this:
if (myDic == null)
{
// change var and var2 to the types of variable they should be, ex:
myDic = new Dictionary<string, List<string>>();
}
string text = SomeFunction(stringValue1, stringValue2, myDic);
or, what is probably the better option, in the declaration of the function SomeFunction add a dictionary as a variable with a default parameter. Just be sure that your function knows what to do if the dictionary is null.
string SomeFunction(string string1, string string2, Dictionary dictionary = null)
{
// method here
}
You can check if the key exists using ContainsKey method and if it returns false you can pass a default value you want:
// replace default(string) with the value you want to pass
// if the key doesn't exist
var value = myDic.ContainsKey(field1.field2) ? myDic[field1.field2] : default(string);
string text = SomeFunction(stringValue1, stringValue2, value);
What you need to do is make sure the dictionary actually contains the given key in the dictionary.
If you need to extract the value by key, use TryGetValue method:
string value;
if (myDict.TryGetValue(key, out value))
{
// Key exists in the dictionary, do something with value.
}
Use one of the following snippets in order to check if dictionary is empty and take some action:
var x = new Dictionary<string, string>();
if (x.Any())
{
//....
}
if (x.ContainsKey("my key"))
{
}
if (x.ContainsValue("my value"))
{
}
if (x.Count > 0)
{
}
I have a function that gets two strings - a key and a value.
I need to parse the value from string to enum.
the key represent which enum I need to use.
I wanted to use "if"s -
if (keyString == "e1")
{
(MyEnum1)Enum.Parse(typeof(MyEnum1), valueString, true);
}
else if (keyString == "e2")
{
(MyEnum2)Enum.Parse(typeof(MyEnum2), valueString, true);
}
else if .....
But then I thought maybe I can create a dictionary of key and enum -
<"e1", MyEnum1>,
<"e2", MyEnum2>,
...
and then use the dictionary's values for the enum parsing
(dic[keyString])Enum.Parse(typeof(dic[keyString]), valueString, true)
but I couldn't do it..
I there any other way?
Just store the type directly in the dictionary (i.e. store the result of typeof(MyEnum1)):
Dictionary<string, Type> KeyToEnum = new Dictionary<string, Type>();
KeyToEnum["e1"] = typeof(MyEnum1);
KeyToEnum["e2"] = typeof(MyEnum2);
Object EnumValue = Enum.Parse(dic[keyString), valueString, true);
// Note that EnumValue is an object, because we can't know at compile time what the type will be.
Note that if instead of "e1", "e2"... you actually had "MyEnum1", "MyEnum2" (i.e. the actual name of the type you could do Type.GetType(MyKey) instead of the dictionary.