Reflection: how to get values from object as List<object> - c#

Using reflection, I need a function that accepts a list of generic objects and print its values
List<Gender> genders = new List<Gender> {
new Gender {
Id: 1,
Name: "Male"
},
new Gender {
Id: 2,
Name: "Female"
}
}
PrintListValues(genders, "Name"); // prints Male, Female
PrintListValues has to accept a list as object. And the list can contain any type of object. As long as the generic object have the property passed in, it should print the value of each item in list.
public static void PrintValues(object listObject)
{
// code here
}
Unfortunately that's the way the project requirement is.
Been scratching my head over this one and can't figure it out. Reflection is too difficult for me. If anyone can give me hint that would be great!

Try this:
public static void PrintListValues(IEnumerable<object> seq, string propName)
{
foreach (var obj in seq)
{
var type = obj.GetType();
var prop = type.GetProperty(propName);
var value = prop.GetValue(obj);
Console.WriteLine(value);
}
}
Disclaimer: To play with reflection, the above code is fine. For a real world situation, there might be a few things to check as that code assumes the "happy path".

You likely just need
var values = anyList.Select(x => x.SomeProperty);
Console.WriteLine(string.Join(Environemnt.NewLine,values));
However if you really need to include a string property name
public IEnumerable<object> GetValues<T>(IEnumerable<T> source, string name)
{
var prop = typeof(T).GetProperty(name) ?? throw new ArgumentNullException("typeof(T).GetProperty(propName)");
return source.Select(x => prop.GetValue(x));
}
...
foreach (var value in GetValues(someList,"SomeProperty"))
Console.WriteLine(value);
// or
Console.WriteLine(string.Join(Environemnt.NewLine,GetValues(someList,"SomeProperty"));

Related

Iterate over a generic type<T>

I don't know if this can be possible, but I will try to explain myself the best way that I can. Thank you for your help.
I'm trying to fit these entity objects in an integration with a third-party.
My problem is, I have these 3 entity type from the third-party, ObjectType1, ObjectType2, ObjectType3 object classes, all of these have the same base, so, my idea in order to no repeat the code several times was to create a fuction that accepts one generic list and inside of it, try to cast to the object type that I want and used to save the information in my principal entity.
I don't know if this can be possible or what would you recommend me to do, because what I'm trying to do is not to repeat the code several times.
Thank you again.
public static List<ItemsToSave> TestList<T>(List<T> listOfT)
{
var itemsToSave = new List<ItemsToSave>();
foreach (var item in listOfT)
{
object obj = null;
switch (listOfT)
{
case List<ObjectType1>:
obj = item as ObjectType1;
break;
case List<ObjectType2>:
obj = item as ObjectType2;
break;
case List<ObjectType3>:
obj = item as ObjectType2;
break;
}
var itemtosaveEntity = new ItemsToSave()
{
FirstName = obj.FirstName,
MiddleName = obj.MiddleName,
LastName = obj.LastName,
};
itemsToSave.Add(itemtosaveEntity);
}
return itemsToSave;
}
Try this
var listOfT = new List<BaseType>();
List<ItemsToSave> itemsToSave = ConvertList(listOfT);
public static List<ItemsToSave> ConvertList<T>(List<T> listOfT) where T : BaseType
{
return
listOfT
.Select(i => new ItemsToSave()
{
FirstName = i.FirstName,
MiddleName = i.MiddleName,
LastName = i.LastName,
})
.ToList();
}
You can define your generic function like this:
public static List<ItemsToSave> TestList<T>(List<T> listOfT) where t : BaseClass
This is is called a 'Where generic constraint', read more Here
That way the type you have in your function will be BaseClass and you can access all properties defined in that class.

Can I change a value of an existing anonymous type [duplicate]

this is my code for example:
var output = new
{
NetSessionId = string.Empty
};
foreach (var property in output.GetType().GetProperties())
{
property.SetValue(output, "Test", null);
}
It occurs an exception: "Property set method not found". I want to know how to create an anonymous type with properties which can be set.
Thanks.
Anonymous type properties are read only and they cannot be set.
Anonymous types provide a convenient way to encapsulate a set of
read-only properties into a single object without having to explicitly
define a type first. The type name is generated by the compiler and is
not available at the source code level. The type of each property is
inferred by the compiler.
Anonymous Types (C# Programming Guide)
How to set value for property of an anonymous object?
Because I was reminded today that nothing is truly immutable when using reflection in combination with knowledge on how certain things are implemented (backing fields for the read-only properties of anonymous types in this case), I thought it wise to add an answer illustrating how the property values of an anonymous object can be changed, by mapping them to their backing fields.
This method relies on a specific convention used by the compiler for naming these backing fields: <xxxxx>i__Field in .NET and <xxxxx> on Mono, with the xxxxx representing the property name. If this convention were to change, the code below will fail (note: it will also fail if you try to feed it something that is not an anonymous type).
public static class AnonymousObjectMutator
{
private const BindingFlags FieldFlags = BindingFlags.NonPublic | BindingFlags.Instance;
private static readonly string[] BackingFieldFormats = { "<{0}>i__Field", "<{0}>" };
public static T Set<T, TProperty>(
this T instance,
Expression<Func<T, TProperty>> propExpression,
TProperty newValue) where T : class
{
var pi = (propExpression.Body as MemberExpression).Member;
var backingFieldNames = BackingFieldFormats.Select(x => string.Format(x, pi.Name)).ToList();
var fi = typeof(T)
.GetFields(FieldFlags)
.FirstOrDefault(f => backingFieldNames.Contains(f.Name));
if (fi == null)
throw new NotSupportedException(string.Format("Cannot find backing field for {0}", pi.Name));
fi.SetValue(instance, newValue);
return instance;
}
}
Sample:
public static void Main(params string[] args)
{
var myAnonInstance = new {
FirstField = "Hello",
AnotherField = 30,
};
Console.WriteLine(myAnonInstance);
myAnonInstance
.Set(x => x.FirstField, "Hello SO")
.Set(x => x.AnotherField, 42);
Console.WriteLine(myAnonInstance);
}
With output:
{ FirstField = Hello, AnotherField = 30 }
{ FirstField = Hello SO, AnotherField = 42 }
A slightly more elaborate version can be found here
If you ever come across a situation where you need a mutable type, instead of messing around with the Anonymous type, you can just use the ExpandoObject:
Example:
var people = new List<Person>
{
new Person { FirstName = "John", LastName = "Doe" },
new Person { FirstName = "Jane", LastName = "Doe" },
new Person { FirstName = "Bob", LastName = "Saget" },
new Person { FirstName = "William", LastName = "Drag" },
new Person { FirstName = "Richard", LastName = "Johnson" },
new Person { FirstName = "Robert", LastName = "Frost" }
};
// Method syntax.
var query = people.Select(p =>
{
dynamic exp = new ExpandoObject();
exp.FirstName = p.FirstName;
exp.LastName = p.LastName;
return exp;
}); // or people.Select(p => GetExpandoObject(p))
// Query syntax.
var query2 = from p in people
select GetExpandoObject(p);
foreach (dynamic person in query2) // query2 or query
{
person.FirstName = "Changed";
Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}
// Used with the query syntax in this example, but may also be used
// with the method syntax just as easily.
private ExpandoObject GetExpandoObject(Person p)
{
dynamic exp = new ExpandoObject();
exp.FirstName = p.FirstName;
exp.LastName = p.LastName;
return exp;
}
I came here being curious about Anonymous Types, and turned out learning a lot from the answers given.
In my answer i will try to synthesize some valuable information i found, and provide information that i did not see in the other answers and that i think will also worth to read for future visitors.
Why is not possible to re-set (out of the box) the values of an anonymously type object?
To better understand the why, it is worth to read what #EricLippert said in a comment to another question about Anonymous Types:
Note that anonymous types in VB are allowed to be partially mutated. In VB you get to state which parts of the anonymous type are mutable; the generated code will not use mutable bits as part of a hash code / equality, so you don't get the "lost in the dictionary" problem. We decided to not implement these extensions in C#.
Plus the text cited by the Accepted Answer from the official C# documentation:
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and is not available at the source code level. The type of each property is inferred by the compiler.
And just to justify a bit the why it is not possible (out of the box) to set the value of a anonymously typed object, let's see what C# in a Nutshell says:
[If you define]
var dude = new { Name = "Bob", Age = 23 };
The compiler translates this to (approximately) the following:
internal class AnonymousGeneratedTypeName
{
private string name; // Actual field name is irrelevant
private int age; // Actual field name is irrelevant
public AnonymousGeneratedTypeName(string name, int age)
{
this.name = name; this.age = age;
}
public string Name { get { return name; } }
public int Age { get { return age; } }
// The Equals and GetHashCode methods are overriden...
// The ToString method is also overriden.
}
...
var dude = AnonymousGeneratedTypeName ("Bob", 23);
But, is it true that once you set the value of an Anonymous Type it is not possible to modify it?
Well, as we can learn from the answer given by #Alex:
nothing is truly immutable when using reflection in combination with knowledge on how certain things are implemented (backing fields for the read-only properties of anonymous types in this case).
If you are curious to see HOW you can modify the value of an anonymously typed object, go and read his answer, it is really worth!
If at the end, you what to stick with the simplicity in the one liner
var dude = new { Name = "Bob", Age = 23 };
and want to be able to modify latter one of dude's properties, you can (in many cases) simply change the var keyword by dynamic. Then you can do
dynamic dude = new { Name = "Bob", Age = 23 };
dude.Name = "John"; // Compiles correctly.
But watch out! var and dynamic are not as similar as they seem at a first look. As already noted in a comment to #B.K. by #MikeBeaton
this doesn't work in the case where you need a typed null value? (i.e. an ExpandoObject can't support that, but an anonymous type can)
There are some SO posts about dynamic vs var.
A suggestion: you can set all properties at once.
The other answers correctly suggest that they are immutable objects (although Alex's answer does show how to get at the backing fields, which is a good, yet messy answer) but they do have constructors exposed, so you can create new instances.
Below, the example takes a template instance and creates new instances of it in the CreateFromAnonymousTemplate function. There are downsides, but the biggest benefit (aside from being able to create these objects!) is that you are sticking to the convention that anonymous types should be immutable.
class Program
{
static void Main(string[] args)
{
// Create a template that defines the anonymous type properties.
var personTemplate = new { Name = "", Age = 0 };
var sam = CreateFromAnonymousTemplate(personTemplate, "Sam", 43);
var sally = CreateFromAnonymousTemplate(personTemplate, "Sally", 24);
}
private static Dictionary<Type, ConstructorInfo> _constructors = new Dictionary<Type, ConstructorInfo>();
// By using T, we get intellisense for our returned objects.
static T CreateFromAnonymousTemplate<T>(T templateReference, params object[] propertyValues)
{
// This is the type of the template. In this case, the anonymous type.
Type anonymousType = templateReference.GetType();
ConstructorInfo anonymousTypeConstructor;
if (_constructors.ContainsKey(anonymousType))
{
anonymousTypeConstructor = _constructors[anonymousType];
if(anonymousTypeConstructor.GetParameters().Length != propertyValues.Length)
throw new ArgumentException("Invalid initialisation properties. Parameters must match type and order of type constructor.", "propertyValues");
}
else
{
PropertyInfo[] properties = anonymousType.GetProperties();
if (properties.Count() != propertyValues.Length)
throw new ArgumentException("Invalid initialisation properties. Parameters must match type and order of type constructor.", "propertyValues");
// Retrieve the property types in order to find the correct constructor (which is the one with all properties as parameters).
Type[] propertyTypes = properties.Select(p => p.PropertyType).ToArray();
// The constructor has parameters for each property on the type.
anonymousTypeConstructor = anonymousType.GetConstructor(propertyTypes);
// We cache the constructor to avoid the overhead of creating it with reflection in the future.
_constructors.Add(anonymousType, anonymousTypeConstructor);
}
return (T)anonymousTypeConstructor.Invoke(propertyValues);
}
}
I had a similar scenario where I needed to assign an error code and message to numerous object types that all SHARE specific nested properties so I don't have to duplicate my methods for reference hoping it helps someone else:
public T AssignErrorMessage<T>(T response, string errorDescription, int errorCode)
{
PropertyInfo ErrorMessagesProperty = response.GetType().GetProperty("ErrorMessage");
if (ErrorMessagesProperty.GetValue(response, null) == null)
ErrorMessagesProperty.SetValue(response, new ErrorMessage());
PropertyInfo ErrorCodeProperty = ErrorMessagesProperty.GetType().GetProperty("code");
ErrorCodeProperty.SetValue(response, errorCode);
PropertyInfo ErrorMessageDescription = ErrorMessagesProperty.GetType().GetProperty("description");
ErrorMessageDescription.SetValue(response, errorDescription);
return response;
}
public class ErrorMessage
{
public int code { get; set; }
public string description { get; set; }
}
An easy way could be to serialize the anonymous object in a Json with NewtonSoft'JsonConverter (JsonConvert.SerializeObject(anonObject)). Then you can change the Json via string manipulation and reserialize it into a new anonymous object that you can assign to the old variable.
A little convolute but really easy to understand for beginners!
Anonymous types are immutable in C#. I don't think you can change the property there.

Getting a dictionary full path to specific key using reflection

I have a situation where I have a nested IDictionary, like this;
class SomeObject {
public IDictionary<string, IDictionary<string, decimal>> Entries { get; set; }
}
So, an object might look like this;
var o = new SomeObject {
Entries = new ... {
["first"] = new ... {
["a"] = 1.0,
["b"] = 2.0
},
["second"] = new ... {
}
}
};
I'm trying to figure out how to get the "path" to one of the nested keys as a collection of strings using a lambda expression. For example ...
class SomeFactory {
public SomeFactory Use<T>(T entity) {
this.Model = entity; return this;
}
public IEnumerable<string> Get<TProperty>(Expression<Func<T, IEnumerable<TProperty>>> selector) {
var properties = ... // get list of properties from [selector] //
}
}
var factory = new SomeFactory();
var list = factory.Use<SomeObject>(o).Get(n => n.Entries["first"]["b"]);
Where the result would be an IEnumerable<string> that had the values ...{"Entries","first","b"}.
Is this possible to do?
Use Case
The reason I am wanting to do this is because I'm working with a library that can issue out commands in a certain way using an object that looks like this (pseudo code);
class Patch {
string Property;
object Value;
Patch[] Nested;
}
Each Patch can take the name of 1 property on an object deserialized from a given point. It will perform a very fast operation to it, considerably faster than loading the entire object from the database, updating it, and saving it again. This is important for a number of reasons at various parts of the program. (This is not an SQL database)
If a nested patch is given, it will not set the value on the top-level property, but instead find the top level property and use it as the launching point to execute the next Patch in the array. This process continues until it gets to the last one, whereupon it makes the change.
So in order to issue a patch to an IDictionary, the whole object graph needs to look something akin to ...
{
"Property": "Entries",
"Nested": [
{
"Property": "first",
"Nested": [
{
"Property": "b",
"Value": 7.0
}
]
}
]
}
This isn't a problem, but it's a bothersome graph to draw up each time. My thought was to make the entire process simpler by being able to construct this graph from just a lambda expression that found the desired destination on the IDictionary object; i.e f(n => n["first"]["b"])
The code below fits your scenario above:
public static IEnumerable<string> Get<T>(Expression<Func<T, object>> selector)
{
var list = new List<string>();
Expression exp = (selector.Body as UnaryExpression).Operand as MethodCallExpression;
while (exp is MethodCallExpression)
{
var call = exp as MethodCallExpression;
var arg = call.Arguments[0].ToString();
if(call.Arguments[0].Type == typeof(string))
{
arg = arg.Substring(1, arg.Length - 2);
}
list.Add(arg);
exp = call.Object as Expression;
}
var member = exp as MemberExpression;
list.Add(member.Member.Name);
list.Reverse();
return list;
}
static void Main(string[] args)
{
var graph = Get<SomeObject>(o => o.Entries["first"]["b"]);
foreach (var node in graph)
{
Console.WriteLine(node);
}
Console.ReadLine();
}
Output is:
Entries
first
b

How to set value for property of an anonymous object?

this is my code for example:
var output = new
{
NetSessionId = string.Empty
};
foreach (var property in output.GetType().GetProperties())
{
property.SetValue(output, "Test", null);
}
It occurs an exception: "Property set method not found". I want to know how to create an anonymous type with properties which can be set.
Thanks.
Anonymous type properties are read only and they cannot be set.
Anonymous types provide a convenient way to encapsulate a set of
read-only properties into a single object without having to explicitly
define a type first. The type name is generated by the compiler and is
not available at the source code level. The type of each property is
inferred by the compiler.
Anonymous Types (C# Programming Guide)
How to set value for property of an anonymous object?
Because I was reminded today that nothing is truly immutable when using reflection in combination with knowledge on how certain things are implemented (backing fields for the read-only properties of anonymous types in this case), I thought it wise to add an answer illustrating how the property values of an anonymous object can be changed, by mapping them to their backing fields.
This method relies on a specific convention used by the compiler for naming these backing fields: <xxxxx>i__Field in .NET and <xxxxx> on Mono, with the xxxxx representing the property name. If this convention were to change, the code below will fail (note: it will also fail if you try to feed it something that is not an anonymous type).
public static class AnonymousObjectMutator
{
private const BindingFlags FieldFlags = BindingFlags.NonPublic | BindingFlags.Instance;
private static readonly string[] BackingFieldFormats = { "<{0}>i__Field", "<{0}>" };
public static T Set<T, TProperty>(
this T instance,
Expression<Func<T, TProperty>> propExpression,
TProperty newValue) where T : class
{
var pi = (propExpression.Body as MemberExpression).Member;
var backingFieldNames = BackingFieldFormats.Select(x => string.Format(x, pi.Name)).ToList();
var fi = typeof(T)
.GetFields(FieldFlags)
.FirstOrDefault(f => backingFieldNames.Contains(f.Name));
if (fi == null)
throw new NotSupportedException(string.Format("Cannot find backing field for {0}", pi.Name));
fi.SetValue(instance, newValue);
return instance;
}
}
Sample:
public static void Main(params string[] args)
{
var myAnonInstance = new {
FirstField = "Hello",
AnotherField = 30,
};
Console.WriteLine(myAnonInstance);
myAnonInstance
.Set(x => x.FirstField, "Hello SO")
.Set(x => x.AnotherField, 42);
Console.WriteLine(myAnonInstance);
}
With output:
{ FirstField = Hello, AnotherField = 30 }
{ FirstField = Hello SO, AnotherField = 42 }
A slightly more elaborate version can be found here
If you ever come across a situation where you need a mutable type, instead of messing around with the Anonymous type, you can just use the ExpandoObject:
Example:
var people = new List<Person>
{
new Person { FirstName = "John", LastName = "Doe" },
new Person { FirstName = "Jane", LastName = "Doe" },
new Person { FirstName = "Bob", LastName = "Saget" },
new Person { FirstName = "William", LastName = "Drag" },
new Person { FirstName = "Richard", LastName = "Johnson" },
new Person { FirstName = "Robert", LastName = "Frost" }
};
// Method syntax.
var query = people.Select(p =>
{
dynamic exp = new ExpandoObject();
exp.FirstName = p.FirstName;
exp.LastName = p.LastName;
return exp;
}); // or people.Select(p => GetExpandoObject(p))
// Query syntax.
var query2 = from p in people
select GetExpandoObject(p);
foreach (dynamic person in query2) // query2 or query
{
person.FirstName = "Changed";
Console.WriteLine("{0} {1}", person.FirstName, person.LastName);
}
// Used with the query syntax in this example, but may also be used
// with the method syntax just as easily.
private ExpandoObject GetExpandoObject(Person p)
{
dynamic exp = new ExpandoObject();
exp.FirstName = p.FirstName;
exp.LastName = p.LastName;
return exp;
}
I came here being curious about Anonymous Types, and turned out learning a lot from the answers given.
In my answer i will try to synthesize some valuable information i found, and provide information that i did not see in the other answers and that i think will also worth to read for future visitors.
Why is not possible to re-set (out of the box) the values of an anonymously type object?
To better understand the why, it is worth to read what #EricLippert said in a comment to another question about Anonymous Types:
Note that anonymous types in VB are allowed to be partially mutated. In VB you get to state which parts of the anonymous type are mutable; the generated code will not use mutable bits as part of a hash code / equality, so you don't get the "lost in the dictionary" problem. We decided to not implement these extensions in C#.
Plus the text cited by the Accepted Answer from the official C# documentation:
Anonymous types provide a convenient way to encapsulate a set of read-only properties into a single object without having to explicitly define a type first. The type name is generated by the compiler and is not available at the source code level. The type of each property is inferred by the compiler.
And just to justify a bit the why it is not possible (out of the box) to set the value of a anonymously typed object, let's see what C# in a Nutshell says:
[If you define]
var dude = new { Name = "Bob", Age = 23 };
The compiler translates this to (approximately) the following:
internal class AnonymousGeneratedTypeName
{
private string name; // Actual field name is irrelevant
private int age; // Actual field name is irrelevant
public AnonymousGeneratedTypeName(string name, int age)
{
this.name = name; this.age = age;
}
public string Name { get { return name; } }
public int Age { get { return age; } }
// The Equals and GetHashCode methods are overriden...
// The ToString method is also overriden.
}
...
var dude = AnonymousGeneratedTypeName ("Bob", 23);
But, is it true that once you set the value of an Anonymous Type it is not possible to modify it?
Well, as we can learn from the answer given by #Alex:
nothing is truly immutable when using reflection in combination with knowledge on how certain things are implemented (backing fields for the read-only properties of anonymous types in this case).
If you are curious to see HOW you can modify the value of an anonymously typed object, go and read his answer, it is really worth!
If at the end, you what to stick with the simplicity in the one liner
var dude = new { Name = "Bob", Age = 23 };
and want to be able to modify latter one of dude's properties, you can (in many cases) simply change the var keyword by dynamic. Then you can do
dynamic dude = new { Name = "Bob", Age = 23 };
dude.Name = "John"; // Compiles correctly.
But watch out! var and dynamic are not as similar as they seem at a first look. As already noted in a comment to #B.K. by #MikeBeaton
this doesn't work in the case where you need a typed null value? (i.e. an ExpandoObject can't support that, but an anonymous type can)
There are some SO posts about dynamic vs var.
A suggestion: you can set all properties at once.
The other answers correctly suggest that they are immutable objects (although Alex's answer does show how to get at the backing fields, which is a good, yet messy answer) but they do have constructors exposed, so you can create new instances.
Below, the example takes a template instance and creates new instances of it in the CreateFromAnonymousTemplate function. There are downsides, but the biggest benefit (aside from being able to create these objects!) is that you are sticking to the convention that anonymous types should be immutable.
class Program
{
static void Main(string[] args)
{
// Create a template that defines the anonymous type properties.
var personTemplate = new { Name = "", Age = 0 };
var sam = CreateFromAnonymousTemplate(personTemplate, "Sam", 43);
var sally = CreateFromAnonymousTemplate(personTemplate, "Sally", 24);
}
private static Dictionary<Type, ConstructorInfo> _constructors = new Dictionary<Type, ConstructorInfo>();
// By using T, we get intellisense for our returned objects.
static T CreateFromAnonymousTemplate<T>(T templateReference, params object[] propertyValues)
{
// This is the type of the template. In this case, the anonymous type.
Type anonymousType = templateReference.GetType();
ConstructorInfo anonymousTypeConstructor;
if (_constructors.ContainsKey(anonymousType))
{
anonymousTypeConstructor = _constructors[anonymousType];
if(anonymousTypeConstructor.GetParameters().Length != propertyValues.Length)
throw new ArgumentException("Invalid initialisation properties. Parameters must match type and order of type constructor.", "propertyValues");
}
else
{
PropertyInfo[] properties = anonymousType.GetProperties();
if (properties.Count() != propertyValues.Length)
throw new ArgumentException("Invalid initialisation properties. Parameters must match type and order of type constructor.", "propertyValues");
// Retrieve the property types in order to find the correct constructor (which is the one with all properties as parameters).
Type[] propertyTypes = properties.Select(p => p.PropertyType).ToArray();
// The constructor has parameters for each property on the type.
anonymousTypeConstructor = anonymousType.GetConstructor(propertyTypes);
// We cache the constructor to avoid the overhead of creating it with reflection in the future.
_constructors.Add(anonymousType, anonymousTypeConstructor);
}
return (T)anonymousTypeConstructor.Invoke(propertyValues);
}
}
I had a similar scenario where I needed to assign an error code and message to numerous object types that all SHARE specific nested properties so I don't have to duplicate my methods for reference hoping it helps someone else:
public T AssignErrorMessage<T>(T response, string errorDescription, int errorCode)
{
PropertyInfo ErrorMessagesProperty = response.GetType().GetProperty("ErrorMessage");
if (ErrorMessagesProperty.GetValue(response, null) == null)
ErrorMessagesProperty.SetValue(response, new ErrorMessage());
PropertyInfo ErrorCodeProperty = ErrorMessagesProperty.GetType().GetProperty("code");
ErrorCodeProperty.SetValue(response, errorCode);
PropertyInfo ErrorMessageDescription = ErrorMessagesProperty.GetType().GetProperty("description");
ErrorMessageDescription.SetValue(response, errorDescription);
return response;
}
public class ErrorMessage
{
public int code { get; set; }
public string description { get; set; }
}
An easy way could be to serialize the anonymous object in a Json with NewtonSoft'JsonConverter (JsonConvert.SerializeObject(anonObject)). Then you can change the Json via string manipulation and reserialize it into a new anonymous object that you can assign to the old variable.
A little convolute but really easy to understand for beginners!
Anonymous types are immutable in C#. I don't think you can change the property there.

HowTo use Dynamic linq with an index instead of a property name

I have an ICollection with objects:
private ObservableCollection<ViewItem> items;
The viewItems have no properties. The data will be accessed via an index with
public object this[int index] {
get{ .... }
set {....}
}
I have a geneal class for filtering. The linq with properies will work fine. I use (the important code only):
Queryable = CreateQueryable((IEnumerable<object>)mItemsSource.SourceCollection, ItemType);
mQuery = Queryable.Where(filterString).Cast<object>();
ilteredCollection = mQuery.ToList();
with:
private static IQueryable CreateQueryable(IEnumerable<object> collection, Type itemType)
{
if (itemType == null) return null;
var queryableList = collection.AsQueryable();
return queryableList.Provider.CreateQuery(
Expression.Call(
typeof(Queryable), "Cast",
new Type[] { itemType },
queryableList.Expression));
}
So I can use a filter string like: Id>10 or Name="abc"
where Id and Name are property names.
But I have also Object in another collection which only have access via index. so I have an where string like:
[0]>10 or [1]="abc"
I didn't find any solution. The only hint I could find is to use:
new(it([idx] as Type)
where idx is element index and Type is a type of this element
e.g.
[0]>10 --> new(it[0] as object)>10
But than I get the error:
{"Operator '=' incompatible with operand types 'DynamicClass1' and 'Int32'"}
Useing a string in my filter like:
new(it[0] as object)>"10"
than the error is:
{"Operator '=' incompatible with operand types 'DynamicClass1' and 'string'"}
So - how can I solve this problem. Because this is a general Filterclass I also don't know the type. So in the as statement I can only use object or something like this.
I hope anyone can help me. Perhaps the dynamic keyword of C# 4.0 will help??
BTW a workaround will be to impement a wrapper in each class with indexer, but this will be a lot of stupid work. And that is something a real programmer don't like ;). I am sure there is a solution!
Cheer up !!
First of all -- How to access Current Instance ?
When parsing a lambda expression with a single unnamed parameter, the members of the unnamed parameter are automatically in scope in the expression string, and the current instance given by the unnamed parameter can be referenced in whole using the keyword it. For example,
customers.Where("Country = #0", country);
is equivalent to
customers.Where("it.Country = #0", country);
Above concept has been explained here.
From above explanation, we can now access the indexer property as it[#0] where #0 is value of index to be passed, as explained below.
//Consider below class
public class Product
{
private NameValueCollection collection = new NameValueCollection();
public string Company { get; set; }
public string Distributor { get; set; }
public int ID { get; set; }
...
public string this[string index]
{
get { return collection[index]; }
set { if(!string.IsNullOrEmpty(value)) collection[index]=value; }
}
}
//Main Code
List<Product> list = new List<Product>();
Product product = new Product() { Company = "Nestle", Distributor = "xyz", ID = 1 };
product["Name"] = "Maggi";
list.Add(product);
var filteredList = list.AsQueryable().Where("it[#0]=#1", "Name", "Maggi"); //Accessing the current item by indexer property
foreach (Product productItem in filteredList)
{
Console.WriteLine(productItem.Company);
}
Hope this helps you !! :)
Your usage of new keyword is wrong.
It does not cast object (nor does as).
Keyword new is used to create new object of anonymous class with the specified properties.
Thus new(it[idx] as Type) will create new object with property Type having the value it[idx]. It is equivalent to C#'s: new { Type = this[idx] }.
As I have already pointed out in Dynamic linq: Is there a way to access object data by index?, you need to cast it in the following manner: Int32(it[0]) > 10 for your pseudo-query [0] > 10.

Categories