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
Related
I have a List of dynamic objects that I am trying to use dynamic Linq on. I am using dynamic objects because I do not know the properties that will be coming into the object. Linq works on my dynamic object, but, to avoid giant hard coding if statements, I would like to use dynamic Linq to search my list. The top half of the code snippet works but I need it to work dynamically so I can create a query string from my properties and filter that way.
public List<dynamic> GetFilteredLocationData(List<dynamic> locationData, string searchTerm){
//Does work
List<dynamic> totalResults = locationData.Where(x => x.Street.ToLower().Contains(searchTerm.ToLower()) ||
x.Street.ToLower().Contains(searchTerm.ToLower()) ||
x.Zip.ToLower().Contains(searchTerm.ToLower()));
//Does not work
var testQueryString = "(Street == \"king\")";
var testResult = locationData.Where(testQueryString);
return totalResults;
}
The runtime error I receive: No property or field 'Street' exists in type 'Object'
That error makes sense as object by default doesn't contain 'Street' but I'd expect the dynamic Linq to behave like the code above it. Is there something I am doing wrong here, or should I take a different approach? I can provide more detail if needed.
Thanks in advance!
Finally I got a working solution! It may not be the most efficient but it works for my needs and allows me to keep the dynamic nature I was hoping to retain. The solution was to drop Linq entirely and use a good old for-each loop. The Important part was the IDictionary which allowed me to search each row for the key value pair. This is the same functionality I was going for, just ditched linq.
public List<dynamic> GetFilteredLocationData(List<dynamic> locationData, string searchTerm){
List<dynamic> totalResults = new List<dynamic>();
List<string> locationProperties = new List<string> {"dynamic properties here, this was filled by call to DB for info pertaining to certain location combined with unique data"}
foreach (var locData in locationData)
{
var currentLoc = locData;
var currentLocDict = (IDictionary<string, object>)currentLoc;
bool containsSearchTerm = CheckIfLocationContainsSearch(currentLocDict, allLocationProperties, searchTerm);
if (containsSearchTerm)
{
totalResults.Add(locData);
}
}
}
public bool CheckIfLocationContainsSearch(IDictionary<string,object> location, List<string> locationProperties, string searchTerm){
foreach (var locProp in locationProperties)
{
if (location[locProp].ToString().ToLower().Contains(searchTerm))
{
return true;
}
}
return false;
}
I know I'm missing something fundamental with either generics or covariance, and I was hoping there is a better way to do what I am doing.
I have a method that takes a list of domain objects and turns it into an HTML table:
public String GenerateTable(List<object> Data, String[] Properties,
String[] ColumnHeaders = null)
{
}
When I call the method, I find myself having to do this:
List<Customer> cust = GetCustomers();
List<object> oCust = new List<object>;
foreach (Customer c in cust)
oCust.Add((object)c);
string table = GenerateTable(oCust, new string[] { "CustNbr", "CustName" });
I believe with covariance I can simply:
List<object> oCust = cust;
But I'm looking for a better solution all-around -- eliminate the necessity to create a completely new list each time I run this method. It's not a performance or memory issue, as these lists are always relatively small, but I'd like to understand what is the best (or at least better) way to accomplish this.
You should change GenerateTable to accept an IEnumerable of objects instead of a list. Then you won't have to convert your Customer list to a list of objects.
public String GenerateTable(IEnumerable<object> Data, String[] Properties, String[] ColumnHeaders = null)
The problem with your original version is that GenerateTable could attempt to add a non-Customer object to the List. IEnumerable works because it is read only. You can read more about it here, if you are interested.
Covariance is only supported in generic interfaces. Since it looks like an IEnumerable would be sufficient you can try to not use a generic at all.
public string GenerateTable(IEnumerable data, string[] properties, string[] columnHeaders = null)
Alternately, you could set up a generic transformation method
public string GenerateRow(Customer customer) { // convert one object here}
public string GenerateTable<T>(List<T> objects, Func<T,string> rowGenerator)
{
// table boilerplate
foreach(var obj in objects) {
output.Append(rowGenerate(customer))
}
}
and then call it with
var table = GenerateTable(customerList, GenerateRow);
to generate your table.
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.
I have come across something pretty complex. I would be obliged if anyone can help.
1) I have to create a List<> of unknown type at compile time. That I have already achieved.
Type customList = typeof(List<>).MakeGenericType(tempType);
object objectList = (List<object>)Activator.CreateInstance(customList);
"temptype" is the custom type thats been already fetched.
2) Now I have PropertyInfo object which is that list from which I have to copy all items to the the instance that I have just created "objectList"
3) Then I need to iterate and access the items of "objectList" as if it were a "System.Generic.List".
Cutting long story short, using reflection I need to extract a property that is a list and have it as an instance for further use. Your suggestions would be appreciated. Thanks in Advance.
Umair
Many of the .NET generic collection classes also implement their non-generic interfaces. I'd make use of these to write your code.
// Create a List<> of unknown type at compile time.
Type customList = typeof(List<>).MakeGenericType(tempType);
IList objectList = (IList)Activator.CreateInstance(customList);
// Copy items from a PropertyInfo list to the object just created
object o = objectThatContainsListToCopyFrom;
PropertyInfo p = o.GetType().GetProperty("PropertyName");
IEnumerable copyFrom = p.GetValue(o, null);
foreach(object item in copyFrom) objectList.Add(item); // Will throw exceptions if the types don't match.
// Iterate and access the items of "objectList"
// (objectList declared above as non-generic IEnumerable)
foreach(object item in objectList) { Debug.WriteLine(item.ToString()); }
Do you think this would help you? Efficient way of updating a collection from another collection
I came up with something similar. I borrowed the SetProperties() method from NullSkull and wrote a simple method that calls the NullSkull SetProperties():
public static List<U> CopyList<T, U>(List<T> fromList, List<U> toList)
{
PropertyInfo[] fromFields = typeof(T).GetProperties();
PropertyInfo[] toFields = typeof(U).GetProperties();
fromList.ForEach(fromobj =>
{
var obj = Activator.CreateInstance(typeof(U));
Util.SetProperties(fromFields, toFields, fromobj, obj);
toList.Add((U)obj);
});
return toList;
}
...so with one line of code I can retrieve a List<desired class> populated with matching values by name from List<source class> as follows:
List<desired class> des = CopyList(source_list, new List<desired class>());
As far as performance goes, I didn't test it, as my requirements call for small lists.
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.