Cast object to KeyValuePair with "generic value"? - c#

I have a ComboBox filled with mixed items of two different types. The types are either
KeyValuePair<Int32, FontFamily>
or
KeyValuePair<Int32, String>
Now there are occasions where I am only interested in the Key of the selected item, which is always an Int32.
What would be the easiest way to access the Key of the selcted item? I am thinking of something like
Int32 key = ((KeyValuepair<Int32, object/T/var/IdontCare>)combobox.SelectedItem).Key;
but that doesn´t work.
So all I have is
Int32 key;
if(combobox.SelectedItem.GetType().Equals(typeof(KeyValuePair<Int32, FontFamily)))
{
key = ((KeyValuePair<Int32, FontFamily)combobox.SelectedItem).Key;
}
else if(combobox.SelectedItem.GetType().Equals(typeof(KeyValuePair<Int32, String)))
{
key = ((KeyValuePair<Int32, String)combobox.SelectedItem).Key;
}
which works, but I wonder if there is a more elegant way?

Casting to dynamic (poor man's reflection) can do the trick
var key = (int) ((dynamic) comboxbox.SelectedItem).Key);

You certainly don't need to use GetType(). You could use:
int key;
var item = combobox.SelectedItem;
if (item is KeyValuePair<int, FontFamily>)
{
key = ((KeyValuePair<int, FontFamily>) item).Key;
}
else if (item is KeyValuePair<int, string>)
{
key = ((KeyValuePair<int, string>) item).Key;
}
I don't think there's really a better way without using reflection or dynamic typing, assuming you can't change the type of the selected items to your own equivalent to KeyValuePair with some non-generic base type or interface.

I guess it's bound in WPF, in that case I would suggest to not use KeyValuePair<TKey,TValue> but instead an own VM class. E.g.
class MyComboItem
{
private String _stringValue;
private FontFamiliy _fontFamilyValue;
public Int32 Key {get;set;}
public object Value => (_fontFamilyValue!=null)?_fontFamilyValue:_stringValue;
}
or you could have an interface like
interface IMyComboItem
{
Int32 Key {get;}
object Value {get;}
}
and implement two VM classes that implement it storing the proper value type.
With proper constructors and so on. Casting as you want achieve isn't possible with generics, and your solution case isn't elegant.

You can create your own class hierarchy like this
public interface IComboBoxItem
{
public int Key { get; }
}
public class ComboBoxItem<T> : IComboBoxItem
{
public T Value { get; set; }
public int Key { get; set; }
}
and your cast will look like this:
key = ((IComboBoxItem)combobox.SelectedItem).Key;

Building on Rich's answer, I used Dynamic successfully. I knew the dictionary type I was binding to (and realistically could have used the dictionary itself, since that was still referenced in my form), but I wanted to create a method to search by the displayname. This will eventually check if the binding source is a datatable too, but for now, this worked well for a <string,?> dictionary.
private void SetComboBoxSelection(ComboBox cmb, string ItemText)
{
if (cmb.DisplayMember.ToLower() == "key" && cmb.ValueMember.ToLower() == "value")
{
foreach (dynamic item in cmb.Items)
if (item.Key == ItemText)
cmb.SelectedItem = item.Value;
}
}

Related

Validating a large dictionary of set strings with user input

I have a profile form that has a lot of user selections and I am sort of stumped on a good approach to validate what the user enters, when passing validation mapping those values to object properties.
For example I have a dictionary
public static Dictionary<string, string> objProfileSelections = new Dictionary<string, string>();
public static string MySelections(string key)
{
objProfileSelections.Add("1", "No Answer");
objProfileSelections.Add("3", "Less Than $25,000");
objProfileSelections.Add("5", "$35,000 to $50,000");
objProfileSelections.Add("7", "$50,000 to $75,000");
objProfileSelections.Add("9", "$75,000 to $100,000");
objProfileSelections.Add("11", "$100,000 to $150,000");
objProfileSelections.Add("13", "$150,000+");
objProfileSelections.Add("2", "No Answer");
objProfileSelections.Add("4", "Less Than $25,000");
objProfileSelections.Add("6", "$35,000 to $50,000");
objProfileSelections.Add("8", "$50,000 to $75,000");
objProfileSelections.Add("10", "$75,000 to $100,000");
objProfileSelections.Add("12", "$100,000 to $150,000");
objProfileSelections.Add("14", "$150,000+");
string item;
objProfileSelections.TryGetValue(key, out item);
return item;
}
Id like to pass in a list of key strings from the user and pass those items to populate an object. The issue is I don't know how to code it so it know which property to go to, I looked at reflection, but I couldn't find any examples that have a set dictionary of values that map to property names.
To make a bit more clear, when a user makes a selection it passes as a parameter in the dictionary, and the dictionary outputs the items. From key 1 comes value No Answer. If the user selected all the check boxes it would be value - (1,3,5,7,9,11,13). I need to extract those values when there is a matching key to a matching property. For example if the user clicks 1,5 but leaves the rest unchecked, how do I know which selections the user made? How do I get the program to know which property to populate based on the results?
*edit
some properties I would like it mapped to
public string MyAnnualIncome{ get; set; }
public List<string> InterestAnnualIncome{ get; set; }
So the first property would be taking one value, and the second property would be taking multiple values.
When a key matches a value comes out the dictionary, I would need the odd values going to MyAnnualIncome and the even values going to InterestAnnualIncome.
so no one is confused odd and even keys are set up for a purpose, odd numbers belonging to a certain group of properties and the even ones belonging to another based on the html selections (even being my selections, odd being what I am interested in)
*Update
Is there a way I can possibly use the keys like 1,3,5 and pass that into a list using the except extension method. Then take the results and use a method to convert the values from enumerated data types to strings?
Hopefully I understood your question.
I would add a small helper class (this is a solution which doesn't use reflection, but uses delegates instead):
public class PropertyModifier
{
private string text;
private Func<string> modifier;
public PropertyModifier(Func<string> modifier)
{
this.modifier = modifier;
}
public PropertyModifier With(string text)
{
PropertyModifier newModifier = new PropertyModifier(modifier);
newModifier.text = text;
return newModifier;
}
public void Modify()
{
modifier(Text);
}
}
Then I would rewrite your code and have the dictionary map to this class instead to string:
public static Dictionary<string, PropertyModifier> objProfileSelections = new Dictionary<string, PropertyModifier>();
public static MyUserProfile Profile; //Assuming this is the object you want to modify
public static string MySelections(string key)
{
PropertyModifier myIncome = new PropertyModifier(text => Profile.MyAnnualIncome = text);
PropertyModifier interestIncome = new PropertyModifier(text => Profile.InterestAnnualIncome.Add(text));
objProfileSelections.Add("1", myIncome.With("No Answer"));
objProfileSelections.Add("3", myIncome.With("Less Than $25,000"));
...
objProfileSelections.Add("2", interestIncome.With("No Answer"));
objProfileSelections.Add("4", interestIncome.With("Less Than $25,000"));
...
}
Then, when processing the user's selection, get the mapped PropertyModifier from the dictionary and call its Modify method.
I tried in this code to illustrate how you can modify the properties of the different classes that may compose a profile. Modifications are done by reflection only, i.e. just providing the class name, the property name that will vary in each class and the string value to be assigned to the property.
Not sure that it fits your expectations :(
Profile profile = new Profile() ;
profile.SetPropertyValue("hair","color","brown") ;
internal class Profile()
{
private Hair hair_ = new Hair();
private Job job_ = new Job ();
internal Hair hair { get { return hair_ ; } }
internal Job job { get { return job_ ; } }
private void SetPropertyValue(string profileItemName, string ItemPropertyName, string value)
{ // it is assumed that the different items (hair or job) of the Profile are accessible
// with a a property
// first find the Item object, i.e. hair or job
object itemObj = this.GetType().GetProperty(profileItemName).GetValue(this,null);
// assign to Item property the input value, e.g. hair.color=Brown
itemObj.GetType().GetProperty(ItemPropertyName).SetValue(itemObj, value, null);
}
}
internal class Hair()
{
private string color_ ;
private string style_ ;
internal string color { get { return color_ ; } set {color_ = value ; } }
internal string style { get { return style_ ; } set {style_ = value ; } }
}

How to write a getter and setter for a Dictionary?

How do you define a getter and setter for complex data types such as a dictionary?
public Dictionary<string, string> Users
{
get
{
return m_Users;
}
set
{
m_Users = value;
}
}
This returns the entire dictionary? Can you write the setter to look and see if a specific key-value pair exists and then if it doesn't, add it. Else update the current key value pair? For the get, can you return a specific key-value pair instead of the whole dictionary?
Use an indexer property (MSDN):
public class YourClass
{
private readonly IDictionary<string, string> _yourDictionary = new Dictionary<string, string>();
public string this[string key]
{
// returns value if exists
get { return _yourDictionary[key]; }
// updates if exists, adds if doesn't exist
set { _yourDictionary[key] = value; }
}
}
Then use like:
var test = new YourClass();
test["Item1"] = "Value1";
It is not possible to do it in a way that would involve only properties. You theoretically could write a setter, but for a getter, you would need to specify a key that you want to retrieve. That is impossible since properties do not accept parameters. Natural way to accomplish what you want would be to use methods:
private Dictionary<string, string> users = new Dictionary<string, string>();
public void Set(string key, string value)
{
if (users.ContainsKey(key))
{
users[key] = value;
}
else
{
users.Add(key, value);
}
}
public string Get(string key)
{
string result = null;
if (users.ContainsKey(key))
{
result = users[key];
}
return result;
}
Alternatively, as others have already said, you could use indexers, but I've always found them a little cumbersome. But I guess it's just a matter of personal preference.
And just for the sake of completeness, this is how a setter could look like, although it's highly unusual and counter-intuitive to have such a property:
public KeyValuePair<string, string> Users
{
set
{
Set(value.Key, value.Value);
}
}
Internally, it uses the Set method from my previous snippet.
It looks like you want an "named indexer". Here's (my) one way to accomplish that using C#.
My approach exposes a property that returns an object (with a default indexer) which will perform the indexing into the appropriate field given the lambdas to do it.
There are reasons you may or not want to use this method, but I'll leave that to you. :)
You won't be able to do that with a property. You'll need to use methods for that, or add an indexer to your class. The get method can't accept a parameter (the key).
Another option, if you want someone to be able to easily add/remove keys to the dictionary but prevent them from setting an entirely new one would be to make the property a read-only property that returns a dictionary created in the constructor. It would be less flexible then adding get/set methods, but in common, simple cases it can do just fine.
It is possible to do so with the setter but highly unrecommended, and is completely impossible with the getter as it takes no parameter to determine what to get.
For the setter you would have to pass a Dictionary<string, string> with a single pair but it goes against what you would expect the getter/setter to usually do and completely stops you setting the entire Dictionary.
A much better way is to use a pair of methods which you can name Get and Set if you so desire.
Dictionary<string, string> param = new Dictionary<string, string>();
public void SetYourParameter(string parametrName, string paramValue)
{
param[parametrName] = paramValue;
}
public string GetYourParameter(string parametrName)
{
// ContainKey ---> It returns value if the key was found
if( param.ContainsKey(parametrName))
return param[parametrName];
else
return null;
}

Convert custom Class to List<>

Scenario:
i have a web form from where i m taking input for Item class now i want to assign values to feature that have return type of list how can i do that.
item value = new item(),
value.feature = serialtextbox.text; //error
foreach ( var item in value) //error
{
item.SerialNo= serialtextbox.text;
}
Item and Item feature classes
Class Item
{
list<Itemfeature> features;
}
class ItemFeature
{
public int SerialNo
{
get { return serialno; }
set { serialno = value; }
}
public int Weight
{
get { return weight; }
set { weight = value; }
}
}
Plz help me out
Note: No language is specified, but it looks like C#. I'm assuming C# in this answer.
It's not really clear what you're trying to do here, but I'll give it a shot. First of all, you're going to want to post the actual code you're using. This code won't even compile, it's loaded with syntax errors.
Let's take a look at your objects first:
class Item
{
List<ItemFeature> features;
}
class ItemFeature
{
public int SerialNo
{
get { return serialno; }
set { serialno = value; }
}
public int Weight
{
get { return weight; }
set { weight = value; }
}
}
You have a custom class, ItemFeature, which consists of a serial number (integer) and a weight (integer). You then have another custom class, Item, which consists of a list of ItemFeatures.
Now it looks like you're trying to add a new ItemFeature to the Item and then loop through all of them and set them again?. Something like this, perhaps?:
Item value = new Item();
value.features.Add(new ItemFeature { SerialNo = int.Parse(serialtextbox.Text) } );
foreach (var item in value.features)
{
item.SerialNo = int.Parse(serialtextbox.Text);
}
(Note that this code is probably as free-hand as your code, so I haven't tested it or anything.)
What I've changed here is:
Setting the SerialNo property, rather than trying to set the ItemFeature directly to a value. You need to dig into the object's property to set a value on that property, not just set it to the entire object.
Converting the input (a string) into the property's type (an int).
Looping through the list, not the Item object itself. The Item object contains a list as a property, but the object itself isn't a list. You can loop through the property, not through the parent object.
A few things to ask/note:
What exactly are you trying to do? You have a list of objects, but you're only setting one and then looping through that one to set it again. Why?
You may want to consider more apt class/property names. Things like "Item" can be a bit unclear.
Your Item class has a public variable, features. This is generally frowned upon. It's better to use a property. That way if you ever have to add logic behind it you won't break compatibility outside of the object itself. The ItemFeature class has properties like this, which is good. They can be additionally shortened by using automatic properties if you'd like, just to keep things clean and simple.
Note that my code isn't doing any input checking on the serialtextbox.Text value. It should be. I presented it in a simpler form as an introductory approach to something that will work under ideal conditions. But something like the following would be better:
var serialValue = 0;
if (!int.TryParse(serialtextbox.Text, out serialValue))
{
// Here you would probably present an error to the user stating that the form field failed validation.
// Maybe even throw an exception? Depends on how you handle errors.
// Mainly, exit the logic flow.
return;
}
var value = new Item();
value.features.Add(new ItemFeature { SerialNo = serialValue } );
Edit: I just noticed that my call to .Add() will actually fail. You'll want to initialize the list before trying to use it. Consider changing the Item class to something like this:
class Item
{
public List<ItemFeature> features { get; set; }
public Item()
{
features = new List<ItemFeature>();
}
}
Two things changed here:
I converted the public member to a property, as previously mentioned.
I added a constructor which initializes the list so that it can be used. Otherwise, being a reference type, it would default to null. So any call to .Add() or any other method on the list would throw a NullReferenceException because there's no object on which to call the method(s).

how to use dictionary two way in c#

public static Dictionary<int, string> dic = new Dictionary<int, string>() {
{1,"anystring1"},
{2,"anystring2"}};
I need to use this
string str= dic[1]; // it is possible
int a=dic["anystring1"]; // My dream is it
Use another Dictionary<> and use it in reverse order of key/value.
I'm a bit late on this one, but LINQ is your friend here:
MyDict.FirstOrDefault(pair => pair.Value == "the value you want").Key;
Allows you to do what you want.
I wish this was in the System library, but it's pretty easy to roll your own.
Below, I'll provide the skeleton of writing such a class, whose usage looks like:
var twoWayDict = new TwoWayDict<string, int>();
twoWayDict["zero"] = 0;
// twoWayDict["zero"] == 0
// twoWayDict.Reverse[0] == "zero"
twoWayDict.Reverse[1] = "one";
// twoWayDict["one"] == 1
// twoWayDict.Reverse[1] == "one"
Keep in mind, one gotcha for a two way dictionary is that you should expect all input to be tightly coupled. In other words, if you re-use a key OR a value, you will erase the data previous linked with either:
twoWayDict["zero"] = 0;
// Then later...
twoWayDict.Reverse[0] = "ZERO";
// Now twoWayDict["ZERO"] == 0
// Later still...
// Exception: Key not found! "zero" was dropped when you re-used value 0
Console.WriteLine(twoWayDict["zero"]);
Finally, here's some sample code. It's minimal - it should act as a foundation for anyone who wants to flesh out their own version. Note that I implement a wrapper class so I can provide a "Reverse" property without directly exposing the internal dictionary.
// Generics note: K indicates "key" type and V indicates "value" type
using System.Collections.Generic;
namespace YourNamespaceHere.Collections
{
public class TwoWayDict<K, V>
{
private Dictionary<K, V> _dictKV;
private Dictionary<V, K> _dictVK;
private ReverseDict _reverseDict;
public TwoWayDict()
{
_dictKV = new Dictionary<K, V>();
_dictVK = new Dictionary<V, K>();
_reverseDict = new ReverseDict(this);
}
public ReverseDict Reverse
{
get { return _reverseDict; }
}
// TwoWayDict[key] -> value
public V this[K key]
{
get { return _dictKV[key]; }
set
{
// Remove any existing key/value pair
Remove(key);
_dictKV[key] = value;
_dictVK[value] = key;
}
}
public void Remove(K key)
{
if (_dictKV.ContainsKey(key))
{
_dictVK.Remove(_dictKV[key]);
_dictKV.Remove(key);
}
}
// Wrapper that allows TwoWayDict to expose a convenient
// 'Reverse' property.
public class ReverseDict
{
private TwoWayDict<K, V> _parent;
public ReverseDict(TwoWayDict<K, V> parent)
{
_parent = parent;
}
public K this[V reverseKey]
{
get { return _parent._dictVK[reverseKey]; }
set { _parent[value] = reverseKey; }
}
public void Remove(V value)
{
if (_parent._dictVK.ContainsKey(value))
{
_parent.Remove(_parent._dictVK[value]);
}
}
}
}
}
That is not what a dictionary is meant to do. Can you think of a definition and instantly find the matching word in your favorite dictionary in O(1) time? If you want a class with that type of functionality (a bidirectional dictionary) you will have to build it yourself (or Google for one of many implementations on the Internet).
I actually use a class that combines an ArrayList with a Dictionary so that I can look up child nodes based on name or order added, and maintain the original order of the objects as they were added.
Objects are added to the ArrayList first, then the index of that object in the ArrayList is added to the dictionary using the desired key.
This allows me to access either by key or position, in a very optimal way, while maintaining the order of the objects as they were added.
Gotcha areas to watch for are adding another object using an existing key, which will orphan the original object and removing any element from the vector which will cause the indices in the Dictionary to become corrupted, pointing to the wrong values.
Just thought I would share my two cents worth - hope it helps someone.

What datatype to use?

I need a collection that
contains a set of objects linked to a double.
The sequence of these pairs should be arbitrary set by me (based on an int I get from the database) and be static throughout the lifecycle.
The number of entries will be small (0 ~ 20) but varying.
The collection should be itteratable.
I don't have to search the collection for anything.
The double will be changed after intialization of the collection.
I would like to work with existing datatypes (no new classes) since it will be used in my asp.net mvc controllers, views and services and I don't want them to all to have a dependency on a library just for this stupid holder class.
I thought
IDictionary<int, KeyvaluePair<TheType, double>>
would do the trick, but then I can't set the double after init.
--Edit--
I found out that the classes generated by the linq 2 sql visual studio thingy are actually partial classes so you can add to them whatever you want. I solved my question by adding a double field to the partial class.
Thanks all for the answers you came up with.
It sounds like you may just want an equivalent of KeyValuePair, but mutable. Given that you're only using it as a pair of values rather than a key-value pair, you could just do:
public class MutablePair<TFirst, TSecond>
{
public TFirst First { get; set; }
public TSecond Second { get; set; }
public MutablePair()
{
}
public MutablePair(TFirst first, TSecond second)
{
First = first;
Second = second;
}
}
This doesn't override GetHashCode or Equals, because you're not actually using those (as it's in a value position).
struct MyPair
{
public object TheType;
public double Value;
}
MyPair[] MyColleccyion = new MyPair[20];
Well, KeyValuePair is immutable (which is a good thing), so you'll have to replace the entire value of KeyValuePair, not just the part of it:
yourDict[10] = new KeyValuePair<TheType, Double>(yourDict[10].Key, newValue);
... or think like Jon Skeet. Gah. :)
How about this
public class ListThing<TKey, TValue> : Dictionary<TKey, TValue>
{
public double DoubleThing { get; set; }
public ListThing(double value)
{
DoubleThing = value;
}
}

Categories