Hi i need to pass my Request.Form as a parameter, but first i have to add some key/value pairs to it. I get the exception that the Collection is readonly.
I've tried:
System.Collections.Specialized.NameValueCollection myform = Request.Form;
and i get the same error.
and i've tried:
foreach(KeyValuePair<string, string> pair in Request.Form)
{
Response.Write(Convert.ToString(pair.Key) + " - " + Convert.ToString(pair.Value) + "<br />");
}
to test if i can pass it one by one to another dictionary, but i get:
System.InvalidCastException: Specified
cast is not valid.
some help, anyone? Thanx
You don't need to cast a string to string. NameValueCollection is built around string keys, and string values. How about a quick extension method:
public static IDictionary<string, string> ToDictionary(this NameValueCollection col)
{
var dict = new Dictionary<string, string>();
foreach (var key in col.Keys)
{
dict.Add(key, col[key]);
}
return dict;
}
That way you can easily go:
var dict = Request.Form.ToDictionary();
dict.Add("key", "value");
If your already using MVC then you can do it with 0 lines of code.
using System.Web.Mvc;
var dictionary = new Dictionary<string, object>();
Request.Form.CopyTo(dictionary);
Andre,
how about:
System.Collections.Specialized.NameValueCollection myform = Request.Form;
IDictionary<string, string> myDictionary =
myform.Cast<string>()
.Select(s => new { Key = s, Value = myform[s] })
.ToDictionary(p => p.Key, p => p.Value);
uses LINQ to keep it all on one 'line'. this could be exrapolated to an extension method of:
public static IDictionary<string, string> ToDictionary(this NameValueCollection col)
{
IDictionary<string, string> myDictionary = new Dictionary<string, string>();
if (col != null)
{
myDictionary =
col.Cast<string>()
.Select(s => new { Key = s, Value = col[s] })
.ToDictionary(p => p.Key, p => p.Value);
}
return myDictionary;
}
hope this helps..
public static IEnumerable<Tuple<string, string>> ToEnumerable(this NameValueCollection collection)
{
return collection
//.Keys
.Cast<string>()
.Select(key => new Tuple<string, string>(key, collection[key]));
}
or
public static Dictionary<string, string> ToDictionary(this NameValueCollection collection)
{
return collection
//.Keys
.Cast<string>()
.ToDictionary(key => key, key => collection[key]));
}
Related
I want to group by my list of dictionaries dynamically just like:
public static List<Dictionary<string, ClassName>> GroupBy(this List<Dictionary<string, ClassName>> list)
{
return list.AsQueryable().GroupBy(i => new { Key1 = i["Key01"].ClassProperty, Key2 = i["Key02"].AnotherClassProperty });
}
but I need to set keys name and numbers dynamically.
I had an idea to create dynamic-typed variable using ExpandoObject like that:
public static List<Dictionary<string, ClassName>> GroupBy(this List<Dictionary<string, ClassName>> list, IEnumerable<string> fieldnames)
{
return list.AsQueryable().GroupBy(i => GetKeys(fieldnames, dict) });
dynamic GetKeys(IEnumerable<string> fieldnames, Dictionary<string, ClassName> dict)
{
IDictionary<string, object> sampleObject = new ExpandoObject();
foreach (var fieldname in fieldnames)
{
sampleObject.Add($"Key{sampleObject.Count}", dict.GetValueOrDefault(fieldname).ClassProperty;
}
return sampleObject;
}
}
I'm trying to learn and practice OOP principles and I need some help with an example to get me over the hump. I have the following code:
using System.Collections.Generic;
namespace Test
{
class Program
{
static void Main()
{
Dictionary<string, string> dictionary = new Dictionary<string, string>();
dictionary.Add("cat", "one");
dictionary.Add("dog", "two");
dictionary.Add("llama", "three");
dictionary.Add("iguana", "four");
var test1 = GetKVP(dictionary, "llama");
var test2 = GetValue(dictionary, "llama");
var test3 = GetPosition(dictionary, "llama");
}
static KeyValuePair<string, string> GetKVP(Dictionary<string, string> dict, string key_to_find)
{
foreach (KeyValuePair<string, string> kvp in dict)
{
if (kvp.Key == key_to_find)
{return kvp;}
}
return new KeyValuePair<string, string>();
}
static string GetValue(Dictionary<string, string> dict, string key_to_find)
{
foreach (KeyValuePair<string, string> kvp in dict)
{
if (kvp.Key == key_to_find)
{return kvp.Value;}
}
return string.Empty;
}
static int GetPosition(Dictionary<string, string> dict, string key_to_find)
{
int counter = 0;
foreach (KeyValuePair<string, string> kvp in dict)
{
if (kvp.Key == key_to_find)
{return counter;}
counter += 1;
}
return -1;
}
}
}
What I'm trying to do is consolidate the code set so that I can have a single method which returns a different data type without duplicating code. Please don't comment on the fact that there are several more efficient ways to search a dictionary, I'm aware that this is not ideal.. I simply mocked up some data and methods to use as an example. For the life of me, I can't really visualize how to implement something like that.
You could try doing this, but I don't think it helps too much:
static R GetResult<R>(Dictionary<string, string> dict, string key_to_find, Func<KeyValuePair<string, string>, R> selector, R otherwise)
{
return dict.Where(kvp => kvp.Key == key_to_find).Select(kvp => selector(kvp)).DefaultIfEmpty(otherwise).First();
}
static KeyValuePair<string, string> GetKVP(Dictionary<string, string> dict, string key_to_find)
{
return GetResult(dict, key_to_find, kvp => kvp, new KeyValuePair<string, string>());
}
static string GetValue(Dictionary<string, string> dict, string key_to_find)
{
return GetResult(dict, key_to_find, kvp => kvp.Value, String.Empty);
}
static int GetPosition(Dictionary<string, string> dict, string key_to_find)
{
return dict.Where(kvp => kvp.Key == key_to_find).Select((kvp, n) => n).DefaultIfEmpty(-1).First();
}
In .net everthing is based on Object, so just return Object and then object could be anything just as you want
here is a sample based on your code
using System.Collections.Generic;
namespace Test
{
class Program
{
static void Main()
{
Dictionary<string, Object> dictionary = new Dictionary<string, string>();
dictionary.Add("cat", "one");
dictionary.Add("dog", "two");
dictionary.Add("llama", "three");
dictionary.Add("iguana", "four");
var test1 = GetWhatEver(dictionary, "llama");
var test2 = GetWhatEver(dictionary, "llama");
var test3 = GetWhatEver(dictionary, "llama");
}
static Object GetWhatEver(Dictionary<string, Object> dict, string key_to_find)
{
foreach (var kvp in dict)
{
if (kvp.Key == key_to_find)
{return kvp.Value;}
}
return null;
}
}
}
Trying to copy values from an existing NameValueCollection object to a Dictionary. I have the following code below to do that but seems the Add does not accept that my keys and values are as Strings
IDictionary<TKey, TValue> dict = new Dictionary<TKey, TValue>();
public void copyFromNameValueCollection (NameValueCollection a)
{
foreach (var k in a.AllKeys)
{
dict.Add(k, a[k]);
}
}
Note: NameValueCollection contains String keys and values and so I simply want to provide here a method to allow copying of those to a generic dictionary.
Extension method plus linq:
public static Dictionary<string, string> ToDictionary(this NameValueCollection nvc) {
return nvc.AllKeys.ToDictionary(k => k, k => nvc[k]);
}
//example
var dictionary = nvc.ToDictionary();
It doesn't make sense to use generics here since you can't assign strings to some arbitrary generic type:
IDictionary<string, string> dict = new Dictionary<string, string>();
public void copyFrom(NameValueCollection a)
{
foreach (var k in a.AllKeys)
{
dict.Add(k, a[k]);
}
}
although you should probably create a method to create a new dictionary instead:
public static IDictionary<string, string> ToDictionary(this NameValueCollection col)
{
IDictionary<string, string> dict = new Dictionary<string, string>();
foreach (var k in col.AllKeys)
{
dict.Add(k, col[k]);
}
return dict;
}
which you can use like:
NameValueCollection nvc = //
var dictionary = nvc.ToDictionary();
If you want a general way of converting the strings in the collection into the required key/value types, you can use type converters:
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>(this NameValueCollection col)
{
var dict = new Dictionary<TKey, TValue>();
var keyConverter = TypeDescriptor.GetConverter(typeof(TKey));
var valueConverter = TypeDescriptor.GetConverter(typeof(TValue));
foreach(string name in col)
{
TKey key = (TKey)keyConverter.ConvertFromString(name);
TValue value = (TValue)valueConverter.ConvertFromString(col[name]);
dict.Add(key, value);
}
return dict;
}
parameters.AllKeys.ToDictionary(t => t, t => parameters[t]);
Use LINQ:
public static IDictionary<string, string> ToDictionary(this NameValueCollection collection)
{
return collection.Cast<string>().ToDictionary(k => k, v => collection[v]);
}
Usage:
IDictionary<string, string> dic = nv.ToDictionary();
Super-Short Version
var dataNvc = HttpUtility.ParseQueryString(data);
var dataCollection = dataNvc.AllKeys.ToDictionary(o => o, o => dataNvc[o]);
If you know that your dictionary is always going to contain strings, specify it to contain strings instead of making your class generic:
IDictionary<string, string> dict = new Dictionary<string, string>();
With this, things will "just work" as written (without the generic method specification).
If you need this to be a generic class, and hold generic data, you need some way to convert from string to TKey and string to TValue. You could provide delegates to your copy method to do this:
public void CopyFrom(NameValueCollection a, Func<string, TKey> keyConvert, Func<string, TValue> valueConvert)
{
foreach(var k in a.AllKeys)
{
dict.Add(keyConvert(k), valueConvert(a[k]));
}
}
You would then need to pass a delegate in that would perform the conversion from string to TValue and string to TKey.
You should not forget about EqualityComparer. But it is not a public property. So, you should use reflection to get it.
public static IEqualityComparer GetEqualityComparer(this NameObjectCollectionBase nameObjectCollection)
{
PropertyInfo propertyInfo = typeof(NameObjectCollectionBase).GetProperty("Comparer", BindingFlags.Instance | BindingFlags.NonPublic);
return (IEqualityComparer)propertyInfo.GetValue(nameObjectCollection);
}
public static IEqualityComparer<string> GetEqualityComparer(this NameValueCollection nameValueCollection)
{
return (IEqualityComparer<string>)((NameObjectCollectionBase)nameValueCollection).GetEqualityComparer();
}
public static Dictionary<string, string> ToDictionary(this NameValueCollection nameValueCollection)
{
Dictionary<string, string> dictionary =
nameValueCollection.AllKeys.ToDictionary(x => x, x => nameValueCollection[x], nameValueCollection.GetEqualityComparer());
return dictionary;
}
I have two methods that almost do the same thing. They get a List<XmlNode> based on state OR state and schoolType and then return a distinct, ordered IEnumerable<KeyValuePair<string,string>>. I know they can be refactored but I'm struggling to determine what type the parameter should be for the linq statement in the return of the method (the last line of each method).
I thank you for your help in advance.
private IEnumerable<KeyValuePair<string, string>> getAreaDropDownDataSource() {
StateInfoXmlDocument stateInfoXmlDocument = new StateInfoXmlDocument();
string schoolTypeXmlPath = string.Format(STATE_AND_SCHOOL_TYPE_XML_PATH, StateOfInterest, ConnectionsLearningSchoolType);
var schoolNodes = new List<XmlNode>(stateInfoXmlDocument.SelectNodes(schoolTypeXmlPath).Cast<XmlNode>());
return schoolNodes.Select(x => new KeyValuePair<string, string>(x.Attributes["idLocation"].Value, x.Value)).OrderBy(x => x.Key).Distinct();
}
private IEnumerable<KeyValuePair<string, string>> getStateOfInterestDropDownDataSource() {
StateInfoXmlDocument stateInfoXmlDocument = new StateInfoXmlDocument();
string schoolTypeXmlPath = string.Format(SCHOOL_TYPE_XML_PATH, ConnectionsLearningSchoolType);
var schoolNodes = new List<XmlNode>(stateInfoXmlDocument.SelectNodes(schoolTypeXmlPath).Cast<XmlNode>());
return schoolNodes.Select(x => new KeyValuePair<string, string>(x.Attributes["stateCode"].Value, x.Attributes["stateName"].Value)).OrderBy(x => x.Key).Distinct();
}
Extract nodes retrieving to separate methods/properties. I also suggest to have different properties/methods for extracting school and state nodes:
private List<XmlNode> GetNodes(string xPath)
{
XmlDocument stateInfoXmlDocument = new XmlDocument();
return new List<XmlNode>(stateInfoXmlDocument.SelectNodes(xPath)
.Cast<XmlNode>());
}
private List<XmlNode> SchoolNodes
{
get { return GetNodes(String.Format(SCHOOL_PATH, LearningSchoolType)); }
}
private List<XmlNode> StateNodes
{
get { return GetNodes(String.Format(STATE_PATH, StateOfInterest)); }
}
Use union of school and state nodes for retrieving area nodes:
private IEnumerable<KeyValuePair<string, string>> GetAreaDropDownDataSource()
{
return SchoolNodes.Union(StateNodes)
.Select(x => new KeyValuePair<string, string>(x.Attributes["idLocation"].Value, x.Value))
.OrderBy(x => x.Key)
.Distinct();
}
private IEnumerable<KeyValuePair<string, string>> GetStateOfInterestDropDownDataSource()
{
return SchoolNodes
.Select(x => new KeyValuePair<string, string>(x.Attributes["stateCode"].Value, x.Attributes["stateName"].Value))
.OrderBy(x => x.Key)
.Distinct();
}
Also you can use different selectors of type Func<XmlNode, KeyValuePair<string, string>> and pass them to method which will create data source:
private IEnumerable<KeyValuePair<string, string>> GetDropDownDataSource(
List<XmlNode> nodes,
Func<XmlNode, KeyValuePair<string, string>> selector)
{
return nodes.Select(selector)
.OrderBy(x => x.Key)
.Distinct();
}
I feel like while they are both returning an IEnumerable<KeyValuePair<string,string>>, these methods are semantically quite different in content. Therefore, I would keep the two methods and extract only the repeated code to a third. Something like:
private List<XmlNode> getSchoolNodes(string xmlPath, params object[] values)
{
StateInfoXmlDocument stateInfoXmlDocument = new StateInfoXmlDocument();
string schoolTypeXmlPath = string.Format(xmlPath, values);
return new List<XmlNode>(stateInfoXmlDocument.SelectNodes(schoolTypeXmlPath).Cast<XmlNode>());
}
private IEnumerable<KeyValuePair<string, string>> getAreaDropDownDataSource() {
var schoolNodes = getSchoolNodes(STATE_AND_SCHOOL_TYPE_XML_PATH, StateOfInterest, ConnectionsLearningSchoolType);
return schoolNodes.Select(x => new KeyValuePair<string, string>(x.Attributes["idLocation"].Value, x.Value)).OrderBy(x => x.Key).Distinct();
}
private IEnumerable<KeyValuePair<string, string>> getStateOfInterestDropDownDataSource() {
var schoolNodes = getSchoolNodes(SCHOOL_TYPE_XML_PATH, ConnectionsLearningSchoolType);
return schoolNodes.Select(x => new KeyValuePair<string, string>(x.Attributes["stateCode"].Value, x.Attributes["stateName"].Value)).OrderBy(x => x.Key).Distinct();
}
You could go as far as the following, but I wonder if this is overengineering the problem and creating overhead calling the two Funcs.
private IEnumerable<KeyValuePair<string, string>> getSchoolNodeDataSource(Func<XmlNode, string> keyFunc, Func<XmlNode, string> valueFunc, string xmlPath, params object[] values)
{
StateInfoXmlDocument stateInfoXmlDocument = new StateInfoXmlDocument();
string schoolTypeXmlPath = string.Format(xmlPath, values);
var schoolNodes = new List<XmlNode>(stateInfoXmlDocument.SelectNodes(schoolTypeXmlPath).Cast<XmlNode>());
return schoolNodes.Select(x => new KeyValuePair<string, string>(keyFunc(x), valueFunc(x))).OrderBy(x => x.Key).Distinct();
}
private IEnumerable<KeyValuePair<string, string>> getAreaDropDownDataSource() {
return getSchoolNodeDataSource(x => x.Attributes["idLocation"].Value, x => x.Value,
STATE_AND_SCHOOL_TYPE_XML_PATH, StateOfInterest, ConnectionsLearningSchoolType);
}
private IEnumerable<KeyValuePair<string, string>> getStateOfInterestDropDownDataSource() {
return getSchoolNodeDataSource(x => x.Attributes["stateCode"].Value, x => x.Attributes["stateName"].Value,
SCHOOL_TYPE_XML_PATH, ConnectionsLearningSchoolType);
}
private IEnumerable<KeyValuePair<string, string>> Foo(
string schoolTypeXmlPath,
Func<T, string> keySelector,
Func<T, string> valueSelector)
{
return (
from XmlNode x in StateInfoXmlDocument().SelectNodes(schoolTypeXmlPath)
orderby x.Key
select new KeyValuePair<string, string>(keySelector(x), valueSelector(x)))
.Distinct()
}
private IEnumerable<KeyValuePair<string, string>> getAreaDropDownDataSource() {
return Foo(
string.Format(STATE_AND_SCHOOL_TYPE_XML_PATH, StateOfInterest, ConnectionsLearningSchoolType),
x => x.Attributes["idLocation"].Value,
x => x.Value);
}
private IEnumerable<KeyValuePair<string, string>> getStateOfInterestDropDownDataSource() {
return Foo(
string.Format(SCHOOL_TYPE_XML_PATH, ConnectionsLearningSchoolType),
x => x.Attributes["stateCode"].Value,
x => x.Attributes["stateName"].Value);
}
As i know, the method to add values for dictionary as below.
Dictionary<string, string> myDict = new Dictionary<string, string>();
myDict.Add("a", "1");
If I declared "myDictDict" as the style below.
IDictionary<string, Dictionary<string, string>> myDictDict = new Dictionary<string, Dictionary<string, string>>();
myDictDict .Add("hello", "tom","cat"); ?// How to add value here.
thank you.
The proper way is like this:
// myDictDict is Dictionary<string, Dictionary<string, string>>
Dictionary<string, string> myDict;
string key = "hello";
if (!myDictDict.TryGetValue(key, out myDict)) {
myDict = new Dictionary<string, string>();
myDictDict.Add(key, myDict);
}
myDict.Add("tom", "cat");
This will extract the dictionary corresponding to the key (hello in your example) or create it if necessary and then will add the key/value pair to that dictionary. You could even extract this into an extension method.
static class Extensions {
public static void AddToNestedDictionary<TKey, TNestedDictionary, TNestedKey, TNestedValue>(
this IDictionary<TKey, TNestedDictionary> dictionary,
TKey key,
TNestedKey nestedKey,
TNestedValue nestedValue
) where TNestedDictionary : IDictionary<TNestedKey, TNestedValue> {
dictionary.AddToNestedDictionary(
key,
nestedKey,
nestedValue,
() => (TNestedDictionary)(IDictionary<TNestedKey, TNestedValue>)
new Dictionary<TNestedKey, TNestedValue>());
}
public static void AddToNestedDictionary<TKey, TNestedDictionary, TNestedKey, TNestedValue>(
this IDictionary<TKey, TNestedDictionary> dictionary,
TKey key,
TNestedKey nestedKey,
TNestedValue nestedValue,
Func<TNestedDictionary> provider
) where TNestedDictionary : IDictionary<TNestedKey, TNestedValue> {
TNestedDictionary nested;
if (!dictionary.TryGetValue(key, out nested)) {
nested = provider();
dictionary.Add(key, nested);
}
nested.Add(nestedKey, nestedValue);
}
}
I left out guarding against null input to keep the idea clear.
Usage:
myDictDict.AddToNestedDictionary(
"hello",
"tom",
"cat",
() => new Dictionary<string, string>()
);
or
myDictDict.AddToNesteDictionary("hello", "tom", "cat");
IDictionary<string,Dictionary<string,string>> myDictDict = new Dictionary<string,Dictionary<string,string>>();
Dictionary<string,string> dict = new Dictionary<string, string>();
dict.Add ("tom", "cat");
myDictDict.Add ("hello", dict);
You can use C# 3's collection initializers, like this:
IDictionary<string, Dictionary<string, string>> myDictDict = new Dictionary<string, Dictionary<string, string>> {
{ "hello", new Dictionary<string, string> { "Tom", "Cat" } }
};
If the dictionary already exists, you can write
dict.Add("hello", new Dictionary<string, string> { "Tom", "Cat" });
Note that this will only work if hello isn't an existing key in the outer dictionary. If it might be, you should use Jason's answer.
To handle this the "simple" way : something like this :
myDictDict.Add("some string", new Dictionary<string, string>());
myDictDict["some string"].Add("another", "string");
To respond directly to the OP's test case : (note the edit added below reflects a desire to correct the syntax of SLaks's answer : code tested and validated against Framework 3.5 Client profile in VS 2010 Beta 2)
// a simple case of creating an instance of a dictionary
// of type <string, string>
// and using .NET 3.0's (FrameWork => 3.5) collection initializer syntax
Dictionary<string, string> twoStringDict = new Dictionary<string, string>()
{
{"key one", "value one"},
{"key two", "value two"}, // note : an "extra" comma does not cause an error here
};
// more complex case as in the question on StackOverFlow
// where dictionary is type <string, Dictionary<string, string>>
// and using .NET 3.0's (FrameWork => 3.5) collection initializer syntax
Dictionary<string, Dictionary<string, string>> myDictDict = new Dictionary<string, Dictionary<string, string>>()
{
{ "key one",
new Dictionary<string, string>() { { "innerKeyOne", "innerValueOne" }}},
{ "key two",
new Dictionary<string, string>() { { "innerKeyTwo", "innerValueTwo" }}}
};
// syntax for adding another key value pair to the complex case
myDictDict.Add("key three", new Dictionary<string, string>() { { "innerKeyThree", "innerValueThree" }});
IDictionary<string, Dictionary<string, string>> myDictDict = new Dictionary<string, Dictionary<string, string>>();
var subDict = new Dictionary<string, string>();
myDictDict .Add("hello", subDict );
subDict.Add("tom", "cat");
You can define an extension method like this :
static void Add(this IDictionary<string, Dictionary<string, string>> dict, string a, string b, string c){
dict.Add(a, new Dictionary<string,string>(){{b,c}};
}
and then use it as :
myDictDict.Add("hello", "tom","cat");