C# properties as array notation - c#

Using JavaScript it's possible to access an object using the dot notation or array notation.
var myArray = {e1:"elem1",e2:"elem2",e3:"elem3",e4:"elem4"};
var val1 = myArray["e1"];
var val2 = myArray.e1;
Is it possible to accomplish this using C#?
This is what I have attempted:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection frmVals)
{
string value;
Owner owner = new Owner();
foreach (var key in frmVals.AllKeys)
{
value = frmVals[key];
owner[key] = value;
}
}

While there is no way to do this exactly with C#. You could change your code in several ways that may accomplish your goal. First, you could use a Dictionary like this:
var something = new Dictionary<string, object>() {
{ "property", "value"},
{ "property1", 1}
};
foreach (var keyVal in something) {
var property = keyVal.Key;
var propertyValue = keyVal.Value;
}
Another option would be to do it dynamically:
dynamic somethingDyn = new System.Dynamic.ExpandoObject();
somethingDyn.property = "value";
somethingDyn.property1 = 1;
var somethingDynDict = (IDictionary<string, object>)somethingDyn;
var propValue = somethingDyn["property"];
foreach (var keyVal in somethingDynDict) {
var property = keyVal.Key;
var propertyValue = keyVal.Value;
}
If you need to iterate through properties on a strongly typed object you could use reflection:
var owner = new Metis.Domain.User();
var properties = owner.GetType().GetProperties();
foreach (var prop in properties) {
object value = prop.GetValue(owner, null);
}

I wouldn't recommend this, but you could put an indexer in your class, accepting a string, then use reflection to read that property. Something like:
public object this[string key]
{
get
{
var prop = typeof(ThisClassName).GetProperty(key);
if (prop != null)
{
return prop.GetValue(this, null);
}
return null;
}
set
{
var prop = typeof(ThisClassName).GetProperty(key);
if (prop != null)
{
prop.SetValue(this, value, null);
}
}
}

Javascript array notation is not something you can use in C#.
You need to use dot notation to access members of an object.
You will need to access each value directly and assign it:
owner.key = frmVals[key];
owner.key2 = frmVals[key2];
There are workarounds - using dictionaries, dynamic objects or even reflection, but the scenario is not a directly supported by C#.

There is no syntactic equivalent possible in C# but there are some ways to approximate the same feature.
You could mimic the indexer type access using a Dictionary but then you'd lose the property-style access. For property-style access, you could do something similar in C# by using an anonymous type, as in:
var myType = new { e1="elem1",e2="elem2",e3="elem3",e4="elem4"};
var val1 = myType.e1;
However, that doesn't create an array or allow array type access and it doesn't allow for modifications to the type after creation.
To get a closer approximation to the JavaScript feature, you may be able to use ExpandoObject to mimic this a little more closely, or you could implement something yourself.
For that, you'd need a class that has a constructor to auto-generate properties from the passed in array and exposes an indexer, which in turn uses reflection to find the named property.
Initialization of this type would be something like:
var myType = new MyType(new[]{
{"e1", "elem1"},
{"e2", "elem2"},
{"e3", "elem3"},
{"e4", "elem4"}});
This assumes there is a sub-type for each element definition (possibly using Tuple or KeyValuePair. The constructor would then be taking an IEnumerable<T> of that type.

Yes, it's possible.
There are two possibilities:
1) The list of keys and values is dynamic.
The array notation is provided by e.g. System.Collections.Generic.Dictionary<string, blah>
The member access notation can be provided through DLR magic and the dynamic keyword.
2) The list of keys and values is static.
Member access notation is already provided by the C# compiler.
Array notation can be had using Reflection (hopefully with a cache to improve performance).
In the static case, member access notation is MUCH faster. In the dynamic case, array notation will be a little faster.

Related

In C#, how do I change a Key-Value-Property's value while recursively traversing an ExpandoObject?

The Problem
Using C#, I need to traverse an object that has been cast to an ExpandoObject from XML and replace any "price" property with a new value.
This object is very unstructured and has many layers of nested nodes (nested ExpandoObjects, actually). More specifically, the hierarchy may look like this:
Product => price, quantity, accessories
Each accessory may have a price and quantity and may itself have accessories, this is why I need recursion.
What I have so far
public ExpandoObject UpdatePricing(ExpandoObject exp)
{
//Is there a price property?
var hasPrice = exp.Any(a => a.Key == "price");
if (hasPrice)
{
//update price here
exp.price = 0; //Some other price
}
//Now loop through the whole object. If any of the properties contain an expando, then call this method again
foreach (var kvp in exp)
{
if (kvp.Value is ExpandoObject)
{
//THIS CODE IS NO GOOD BECAUSE kvp.Value has no setter!!
kvp.Value = UpdatePricing(kvp.Value);
}
}
return exp;
}
The problem I run into is that the kvp.Value has no setter, so I can't run this method recursively.
Any suggestions are appreciated. Thanks!
Since ExpandoObject implements IDictionary<string, Object> things can get a bit easier. We can also change the return type to void because we don't need to reassign the result.
void UpdatePrice(ExpandoObject expando, decimal price)
{
var map = (IDictionary<string, Object>)expando;
if (map.ContainsKey("price"))
map["price"] = price;
foreach (var value in map.Values)
{
if (value is ExpandoObject)
UpdatePrice((ExpandoObject)value, price);
}
}
I don't know much about ExpandoObject. But like most dictionary implementations, I assume that in general if you want your key-value pair to be updated to have a different value, you need to go through the dictionary interface.
Note that you (probably) won't be allowed to modify the dictionary while you're enumerating its contents. So you'll need to build a list of elements to update and do that in a separate operation.
For example:
List<string> keysToUpdate = new List<string>();
foreach (var kvp in exp)
{
if (kvp.Value is ExpandoObject)
{
keysToUpdate.Add(kvp.Key);
}
}
foreach (string key in keysToUpdate)
{
exp[key] = UpdatePricing(exp[key]);
}
You could also keep the whole KeyValuePair value in your list, to avoid the second retrieval of the value, but I'm guessing that's not an important optimization here.
I just ran a little test on this and was able to get it to work by having the expando be dynamic:
public static ExpandoObject DoWork(ExpandoObject obj)
{
dynamic expando = obj;
//update price
if (obj.Any(c => c.Key == "price"))
expando.price = 354.11D;
foreach (var item in expando)
{
if (item.Value is ExpandoObject)
{
//call recursively
DoWork(item.Value);
}
}
return expando;
}
it elimitates type safety, but it looks like you don't have that luxury anyways, dynamic is the best way to interact with expandos in fact according to MSDN:
"In C#, to enable late binding for an instance of the ExpandoObject
class, you must use the dynamic keyword. For more information, see
Using Type dynamic (C# Programming Guide)."
this means that if you don't use the dynamic keyword, you are running the Expando in the CLR instead of the DLR which will have some odd consequences like not being able to set values. Hopefully this helps.

Linq anonymous properties over parameter

Is it possible select an anonymous type via list of properties as parameter. The method should look like:
public void TestLinq(List<"Properties"> properties, List<Data> data)
{
var dat = from d in data select new { properties };
}
I know the description sounds clumsy but I hope I get some help.
It would be important to know the term I have to look for this topic.
You can use the Dynamic LINQ query library (download the sample) to create the list of properties in your projection, like so:
public dynamic TestLinq(IEnumerable<Data> data, IEnumerable<string> properties)
{
// Validate parameters.
if (properties == null) throw new ArgumentNullException("properties");
if (data == null) throw new ArgumentNullException("data");
// Construct the field list.
var fields = new StringBuilder();
foreach (string p in properties) fields.AppendFormat("{0},", property);
// Throw an exception if there are no items.
if (fields.Length == 0) throw new ArgumentException(
"The properties enumeration contains no elements.", "properties");
// Remove the last comma.
fields.Length--;
// Select the items and return. Create the
// projection here.
return data.Select("new(" + fields + ")");
}
Note that the return type is of type dynamic, so you'll have no compile-time checking, and unless you're duck-typing, you probably won't have much knowledge of the fields.
You might be better off creating strong types for this, depending on your needs (if this is based on user-input, then you can't obviously).
Here you go, this is based on this answer https://stackoverflow.com/a/5310828/491950
List<string> properties = new List<string>() { {"ResultPrefix"}, {"ProfileResult"}};
foreach (dynamic d in ListProperties(properties, cellValues))
{
Console.WriteLine(d.ResultPrefix);
}
public static List<dynamic> ListProperties(List<string> properties, List<ChemistryResult> chemistryResults)
{
List<dynamic> output = new List<dynamic>();
foreach (ChemistryResult chemistryResult in chemistryResults)
{
IDictionary<string, Object> result = new ExpandoObject();
foreach (string property in properties)
{
PropertyInfo propertyInfo = typeof(ChemistryResult).GetProperty(property);
result[property] = propertyInfo.GetValue(chemistryResult);
}
output.Add(result);
}
return output;
}
You cannot use anonymous types in a method signature. It cannot be used as a parameter or the return type.
What you could do, is declare the parameter as dynamic, but dynamic can get really sticky, so I recommend avoiding it. You could have a List<dynamic> parameter, then you will be able to access members of the type, but you will not get type checking at compile time.
Another option it to use IEnumerable or IList. Using either of these will allow you to access the members of the collection without knowing the type. This is safer, as you have all of your compile time checks, but will not allow you to access members or the anonymous type.
But really, you should just convert your anonymous type into a real class so you can make your life easier.
I am sorry for the confusion. The outcome should be a csv that's right. The user should be able to define the order of the columns. But for me it was very difficult to formulate a good question. I am looking for a solution with expresisons not with reflection. My Idea was to generate a List of anonymous objects (with the right order) and out of them I wanted to create the csv. So I know the following is working:
public void Get(List<Value> data,Expression<Func<Value, T>> converter)
{
var dat = from d in data
select
new
{
converter
};
}
Is it possible to safe the Expression> converter in a property and combine many of them to one? So I would get the corret order

What are alternatives to declaring data structure in functions?

Is there a good existing or upcoming alternative in C# to declaring data structures in methods? It's possible to use anonymous types, but there are difficulties with declaring them. Let's say I have a hypothetical class:
class ThingsManager
{
private void DoThings(IEnumerable<Thing> things)
{
var thingLocations = new Dictionary<string, string>();
foreach(var thing in things)
{
// some complicated logic and checks for current thing;
// if current thing satisfies all conditions:
var thingName = thing.Name;
var thingLocation = location; // taken somewhere from upper lines
thingLocations.Add(thingName, thingLocation);
}
// ... later
foreach(var thingLocation in thingLocations)
{
// here I don't know what is the key and what does the value mean.
// I could use Linq and anonymous types, but sometimes it is clearer
// to use foreach if the logic is complicated
}
}
}
Now, what I'd like to see:
class ThingsManager
{
private void DoThings(IEnumerable<Thing> things)
{
struct ThingLocations
{
string ThingName {get;set;}
string Location {get;set;}
}
var thingLocations = new List<ThingLocations>();
foreach(var thing in things)
{
// some complicated logic and checks for current thing;
// if current thing satisfies all conditions:
var thingName = thing.Name;
var thingLocation = location; // taken somewhere from upper lines
thingLocations.Add(new ThingLocation(thingName, thingLocation));
}
// ... later
foreach(var thingLocation in thingLocations)
{
// now here I can use thingLocation.ThingName
// or thingLocation.Location
}
}
}
I could also declare the structure in the class, but it doesn't make sense to use it anywhere except in my function. It would be better if my function were the only place where I could use this data structure. I'm looking for a better way to handle such situations, or at least be able to declare anonymous types.
Anonymous types would help with the naming aspect, but you would have to translate the input into your anonymous type and the type would remain internal to the method scope.
// Assumes thingLocation comes from somewhere...
var thingLocations = things
.Select(t => new { ThingName = t.Name, Location = new ThingLocation(t.Name, thingLocation) } );
It is done using the Select extension method in order to project to an anonymous type.
You can declare anonymous types without linq, but you will find it annoying trying to add those to lists / dictionaries:
var me = new { Name = "Adam", Age = 27 };
I'm going on record to say that I wouldn't take this approach, personally I'd either use anonymous types, a Tuple<string, string>, or a custom type.
Failing all of that, and if you don't mind firing up the DLR, you could use an ExpandoObject:
class Thing
{
public string Name;
}
static void Main(string[] args)
{
var things = new List<Thing>() { new Thing { Name = "Adam" } };
var thingLocations = new List<dynamic>();
foreach (var thing in things)
{
dynamic location = new ExpandoObject();
location.Name = thing.Name;
location.Location = "here";
thingLocations.Add(location);
}
// ... later
foreach(var thingLocation in thingLocations)
{
Console.WriteLine(thingLocation.Name);
Console.WriteLine(thingLocation.Location);
}
Console.ReadLine();
}
This allows you to dynamically add properties as you need them by declaring them on the spot. You can then use these later because ExpandoObject provides the plumbing to the DLR when the DLR asks for a member by name.
C# does indeed support Anonymous Types, but the real answer is:
No, you can't do that in C#. Just declare the struct as private right above your method and forget about it.

How do I get key/value of a Dictionnary with an Iterator?

//mDIco is a Dictionnary with string as keys and homemade class (cAsso) as values
IEnumerator iterdico = mDico.GetEnumerator();
iterdico.Reset();
while (iterdico.MoveNext())
{
var asso = iterdico.Current as cAsso;
if (asso != null)
{
//Code
}
}
I thought this would work, but obviously it doesnt. So how I do i get access to the class which is contained into the value of my dictionnary?
The problem is that you are relying on the non-generic IEnumerator interface, which doesn't reveal the real element-type (its Current property is of type object). Use the generic interface (IEnumerator<T>, which does make the element-type easily discoverable) instead, and you will be fine.
Of course, you don't need any special effort for this. The Dictionary<,> class implements the IEnumerable interface explicitly. Its 'implicit' GetEnumerator method returns an enumerator that is strongly typed (a nested type that implements the generic interface), which is what we want.
So it's fine to use implicit typing all the way and let the compiler figure things out.
// Actually a Dictionary<string, cAsso>.Enumerator
// which in turn is an IEnumerator<KeyValuePair<string, cAsso>>
using(var iterdico = mDico.GetEnumerator())
{
while (iterdico.MoveNext())
{
// var = KeyValuePair<string, cAsso>
var kvp = iterdico.Current;
// var = string
var key = kvp.Key;
// var = cAsso
var value = kvp.Value;
...
}
}
EDIT:
A few other peripheral points:
In general, you should Dispose of enumerators, typically with a using block.
The use of the Reset method on enumerators is not recommended. In fact, in this particular case, it is useless.
Note that the element-type of the dictionary's enumerator is a Key-Value pair, not the value itself. if you are only interested in the values, enumerate the sequence returned by the dictionary's Value property.
As Davide Piras points out, in most cases, you just want a normal foreach loop instead of messing around with the enumerator yourself.
foreach(KeyValuePair<string, cAsso> kvp in mDico)
{
// kvp.Key is string
// kvp.Value is cAsso
}
foreach (var kvp in mDico)
{
var asso = kvp.Value;
...
}

how to add an associative index to an array. c#

i have an array of custom objects. i'd like to be able to reference this array by a particular data member, for instance myArrary["Item1"]
"Item1" is actually the value stored in the Name property of this custom type and I can write a predicate to mark the appropriate array item. However I am unclear as to how to let the array know i'd like to use this predicate to find the array item.
I'd like to just use a dictionary or hashtable or NameValuePair for this array, and get around this whole problem but it's generated and it must remain as CustomObj[]. i'm also trying to avoid loading a dictionary from this array as it's going to happen many times and there could be many objects in it.
For clarification
myArray[5] = new CustomObj() // easy!
myArray["ItemName"] = new CustomObj(); // how to do this?
Can the above be done? I'm really just looking for something similar to how DataRow.Columns["MyColumnName"] works
Thanks for the advice.
What you really want is an OrderedDictionary. The version that .NET provides in System.Collections.Specialized is not generic - however there is a generic version on CodeProject that you could use. Internally, this is really just a hashtable married to a list ... but it is exposed in a uniform manner.
If you really want to avoid using a dictionary - you're going to have to live with O(n) lookup performance for an item by key. In that case, stick with an array or list and just use the LINQ Where() method to lookup a value. You can use either First() or Single() depending on whether duplicate entries are expected.
var myArrayOfCustom = ...
var item = myArrayOfCustom.Where( x => x.Name = "yourSearchValue" ).First();
It's easy enough to wrap this functionality into a class so that external consumers are not burdened by this knowledge, and can use simple indexers to access the data. You could then add features like memoization if you expect the same values are going to be accessed frequently. In this way you could amortize the cost of building the underlying lookup dictionary over multiple accesses.
If you do not want to use "Dictionary", then you should create class "myArrary" with data mass storage functionality and add indexers of type "int" for index access and of type "string" for associative access.
public CustomObj this [string index]
{
get
{
return data[searchIdxByName(index)];
}
set
{
data[searchIdxByName(index)] = value;
}
}
First link in google for indexers is: http://www.csharphelp.com/2006/04/c-indexers/
you could use a dictionary for this, although it might not be the best solution in the world this is the first i came up with.
Dictionary<string, int> d = new Dictionary<string, int>();
d.Add("cat", 2);
d.Add("dog", 1);
d.Add("llama", 0);
d.Add("iguana", -1);
the ints could be objects, what you like :)
http://dotnetperls.com/dictionary-keys
Perhaps OrderedDictionary is what you're looking for.
you can use HashTable ;
System.Collections.Hashtable o_Hash_Table = new Hashtable();
o_Hash_Table.Add("Key", "Value");
There is a class in the System.Collections namespace called Dictionary<K,V> that you should use.
var d = new Dictionary<string, MyObj>();
MyObj o = d["a string variable"];
Another way would be to code two methods/a property:
public MyObj this[string index]
{
get
{
foreach (var o in My_Enumerable)
{
if (o.Name == index)
{
return o;
}
}
}
set
{
foreach (var o in My_Enumerable)
{
if (o.Name == index)
{
var i = My_Enumerable.IndexOf(0);
My_Enumerable.Remove(0);
My_Enumerable.Add(value);
}
}
}
}
I hope it helps!
It depends on the collection, some collections allow accessing by name and some don't. Accessing with strings is only meaningful when the collection has data stored, the column collection identifies columns by their name, thus allowing you to select a column by its name. In a normal array this would not work because items are only identified by their index number.
My best recommendation, if you can't change it to use a dictionary, is to either use a Linq expression:
var item1 = myArray.Where(x => x.Name == "Item1").FirstOrDefault();
or, make an extension method that uses a linq expression:
public static class CustomObjExtensions
{
public static CustomObj Get(this CustomObj[] Array, string Name)
{
Array.Where(x => x.Name == Name).FirstOrDefault();
}
}
then in your app:
var item2 = myArray.Get("Item2");
Note however that performance wouldn't be as good as using a dictionary, since behind the scenes .NET will just loop through the list until it finds a match, so if your list isn't going to change frequently, then you could just make a Dictionary instead.
I have two ideas:
1) I'm not sure you're aware but you can copy dictionary objects to an array like so:
Dictionary dict = new Dictionary();
dict.Add("tesT",40);
int[] myints = new int[dict.Count];
dict.Values.CopyTo(myints, 0);
This might allow you to use a Dictionary for everything while still keeping the output as an array.
2) You could also actually create a DataTable programmatically if that's the exact functionality you want:
DataTable dt = new DataTable();
DataColumn dc1 = new DataColumn("ID", typeof(int));
DataColumn dc2 = new DataColumn("Name", typeof(string));
dt.Columns.Add(dc1);
dt.Columns.Add(dc2);
DataRow row = dt.NewRow();
row["ID"] = 100;
row["Name"] = "Test";
dt.Rows.Add(row);
You could also create this outside of the method so you don't have to make the table over again every time.

Categories

Resources