In my c# code, I have an iteration over a Dictionary and want to achieve something like so using Classes
MyModel othermodel = new MyModel();
Dictionary<string, string> mydictionary = new Dictionary<string, string>()
{
{"n1", "Item"},
{"n2", "Second"},
{"n3", "Third"},
{"n4", "Fourth"},
{"n5", "Fith"},
{"n6", "Sixth"},
{"n7", "Seventh"},
{"n8", "Eighth"},
{"n9", "Ninth"},
{"n0", "Tenth"},
{"n11", "Eleventh"}
};
foreach (var dicitem in mydictionary.ToArray())
{
foreach (MyModel.NewItem.(mydictionary[dicitem].Value) item in othermodel.(mydictionary[dicitem].Key))
{
...
}
}
So my result would be:
first iteration:
foreach (MyModel.NewItem.Item item in othermodel.n1)
{
...
}
second iteration:
foreach (MyModel.NewItem.Second item in othermodel.n2)
{
...
}
...
If there is a way to do this, any help would be appreciated.
Accessing object properties via its names can be done using Reflection, doesn't matter where these names come from (dictionary, array, ...)
Little example here:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
then to access the Name property you do:
var me = new Person {Name = "John", Age = 33};
var propertyName = "Name";
var propertyInfo = typeof(Person).GetProperty(propertyName);
var propertyValue = propertyInfo?.GetValue(me) as string;
Using the upper code, you create one Propertynfo.
If you want to read more properties of the same object, it is better to read all PropertyInfo objects at once:
var me = new Person {Name = "John", Age = 33};
var propertiesInfo = typeof(Person).GetProperties();
var propertyName = "Name";
var nameProperty = propertiesInfo
.Single(p => p.Name == propertyName);
var name = nameProperty.GetValue(me) as string;
//faster approach
var age = (int)propertiesInfo
.Single(p => p.Name == "Age")
.GetValue(me);
Be be aware that in this example, I suppose that the property with specific name exists, so I simply called Single. In different situation however, it may require you to check the existence of property before accessing it.
Related
There are a lot of answers for this using a single Type with interfaces and abstract classes which all work fine for one generic T value. What I am trying to achieve I have not seen and am wondering if anyone has an idea.
Scenario
public class Field<T>
{
public Expression<Func<T,object>> FieldName { get; set; }
}
public class FValue<T, F> : Field<T>
{
public F FieldValue { get; set; }
}
//Test
var fieldList = new List<Field<Person>>();
fieldList.Add(new FValue<Person, DateTime> { FieldName=x=>x.SomeDate, FieldValue=DateTime.Now });
fieldList.Add(new FValue<Person, string> { FieldName=x=>x.SomeData, FieldValue="test" });
Ideally i want to do the following:-
The list will contain the same type for T, the type for F will change to various types like date,string etc.
When iterating over the list i want both the FieldName and FieldValue
I can't start the list using new <List<FValue<Persion,string>>();
for the obvious reason that all F values will have to be string.
Also when obtaining the FieldName somehow the value should be casted to Expression<Func<T,F>>.
Any suggestions would be appreciated.
Whenever you want to use generics you need a specific reason to use it. See this answer about when to use Generics
What is cool about generics, why use them?
As you can see in the link, one of the main reason is to have type-safe properties. This also means that your class will be limited to the specific type. And taking this in consideration, the usages of your class will be limited.
Here is how I could use your class with limited usages that don't require (boxing/unboxing), but still requires casting
private static void UseFieldList<T>(List<Field<T>> fieldList)
{
foreach (var field in fieldList)
{
var propName = field.FieldNameText;
var textField = field as FValue<T, string>;
if (textField != null)
{
// Now can use string specific functions without (boxing/unboxing)
Console.WriteLine(propName + " " + textField.FieldValue );
continue;
}
var dateField = field as FValue<T, DateTime>;
if (dateField != null)
{
// Now can use date specific functions without (boxing/unboxing)
Console.WriteLine(propName + " " + dateField.FieldValue.ToShortDateString());
continue;
}
throw new NotSupportedException("The type of the field is not supported: " + field.GetType().Name);
}
}
To get the name out of a expression you can see the answer here
Retrieving Property name from lambda expression
And to use this I would change the way you are creating the objects to something similar to the usages of Tuple:
// Newer code storing name
fieldList.Add(FValue<Person>.Create(x => x.DateOfBirth, DateTime.Now ));
fieldList.Add(FValue<Person>.Create(x => x.Name, "test"));
// Old code storing expression instead of name
fieldList.Add(new FValue<Person, DateTime> { FieldName = x => x.DateOfBirth, FieldValue = DateTime.Now });
fieldList.Add(new FValue<Person, string> { FieldName = x => x.Name, FieldValue = "test" });
// Not supported Type Int
fieldList.Add(new FValue<Person, int> {FieldName = x => x.Name, FieldValue = 12});
And here is the factory class
public class FValue<T>
{
public static Field<T> Create<F>(Expression<Func<T, F>> fieldNameExpression, F value)
{
return new FValue<T, F>
{
FieldNameText = GetPropertyInfo(fieldNameExpression).Name,
FieldValue = value
};
}
}
Results of the console:
DateOfBirth 1/19/2017
Name test
x => Convert(x.DateOfBirth) 1/19/2017
x => x.Name test
The type of the field is not supported: FValue`2
I'm not sure I see a way around this one without using Reflection. Using these classes:
public class Field<T>
{
public Expression<Func<T, object>> FieldName { get; set; }
}
public class FValue<T, F> : Field<T>
{
public F FieldValue { get; set; }
}
You can iterate over them like so:
var list = new List<Field<string>>();
list.Add(new FValue<string, int>() { FieldName = null, FieldValue = 5 });
foreach (var x in list)
{
Type[] types = x.GetType().GetGenericArguments();
// Dirty check to confirm this is an FValue not a Field
if (types.Length == 2)
{
var fieldName = x.FieldName;
object fieldValue = x.GetType().GetProperty("FieldValue").GetValue(x);
// fieldValue will be "5"
}
}
I have a list of dictionaries which contains student data
It is something like
List<Dictionary<string, object>> students = new List<Dictionary<string, object>>();
Dictionary<string, object> std1 = new Dictionary<string, object>();
std1["name"] = "sai";
std1["age"] = 22;
std1["gender"] = "male";
students.Add(std1);
Dictionary<string, object> std2 = new Dictionary<string, object>();
std2["name"] = "Julia";
std2["gender"] = "female";
students.Add(std2);
Dictionary<string, object> std3 = new Dictionary<string, object>();
std3 ["name"] = "sunny";
std3 ["age"] = 23;
students.Add(std3);
And I want to sort the list of students based on either name, age or gender, I am trying something like this:
var ordered = students.OrderBy(x => x["name"]);
If I try with either age or gender it is returning an error that key is not found, as std2 doesn't have age and std3 doesn't have gender.
I need all the records even it doesn't contain the value for sorted key, Any way to solve this problem, Thanks in advance.
It is better to create a class like this:
public class YourClass
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
Then:
List<YourClass> students = new List<YourClass>();
YourClass std1 = new YourClass();
std1.Name = "sai";
std1.Age = 22;
std1.Gender = "male";
students.Add(std1);
yourClass std2 = new yourClass();
std2.Name = "Julia";
std2.Gender = "female";
students.Add(std2);
yourClass std3 = new yourClass();
std3.Name = "sunny";
std3.Age = 23;
students.Add(std3);
var ordered = students.OrderBy(x => x.Name);
This arrangement stores the same data you had in multiple dictionaries. However, it's far more clear and understandable.
If you want to sort by a key that is not present in all of the dictionaries, you'll need to return a default value instead, for example 0.
var ordered = students.OrderBy(dict =>
{
string name;
if (!dict.TryGetValue("name", out name))
return "";
return name;
});
Shorter version using the conditional ternary operator:
var ordered = students.OrderBy(dict =>
{
string name;
return dict.TryGetValue("name", out name) ? name : 0;
});
I use Dictionary.TryGetValue(...) which returns a bool depicting whether the key was found in the dictionary and its value returned.
You can solve this problem by supplying a GetOptional method that returns some default object in situations when the dictionary does not have a specific key:
V GetOptional<K,V>(IDictionary<K,V> d, K key, V absent) {
V res;
return d.TryGetValue(key, out res) ? res : absent;
}
Now you can sort like this:
var byName = students.OrderBy(x => GetOptional<string,object>(x, "name", "----"));
var byAge = students.OrderBy(x => GetOptional<string,object>(x, "age", "10000"));
Note: Using dictionaries like this gives you flexibility at the expense of clarity. It is usually better to define a special Student type, rather than using a universal collection of key-value pairs.
I want to create a query of type Expression that gets some columns of an entity from Entity Framework.
Assume we have two classes like this:
public class Parent
{
public int Id { get; set; }
public string Name { get; set; }
public Child MyChild { get; set; }
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
}
And we have an IQueryable list of Parent:
var q = new List<Parent>()
{
new Parent {Id = 1, Name = "a", Number = 1, MyChild=new Child{Id=11,Name="Child_a",Number=2}},
new Parent {Id = 2, Name = "b", Number = 1, MyChild=new Child{Id=22,Name="Child_b",Number=2}},
new Parent {Id = 3, Name = "c", Number = 1, MyChild=new Child{Id=33,Name="Child_c",Number=2}},
}.AsQueryable();
I want to get a list of those properties of q that user determines them. For example user determines that he needs Parent.Name and Parent.MyChils.Name. So I should give the user a list of anonymous type like this:
{"a","Child_a"}
{"b","Child_b"}
{"c","Child_c"}
If the Parent entity doesn't contain any foreign key property (in this example MyChild property) it is so easy to create an expression property that takes some properties of Parent dynamically. I have a code that gets some properties of Person without MyChild property of it:
var columns = new List<string> { "Id", "Name" };
var xParam = Expression.Parameter(typeof(Parent), "x");
var sourceProperties = columns.ToDictionary(name => name,
name => q.ElementType.GetProperty(name));
var dynamicType = LinqRuntimeTypeBuilder.GetDynamicType(sourceProperties.Values);
var bindings =
dynamicType.GetFields()
.Select(p => Expression.Bind(p, Expression.Property(xParam, sourceProperties[p.Name])))
.OfType<MemberBinding>();
var newExpr = Expression.New(dynamicType.GetConstructor(Type.EmptyTypes));
Expression selector = Expression.Lambda(Expression.MemberInit(
Expression.New(dynamicType.GetConstructor(Type.EmptyTypes)), bindings), xParam);
var body = Expression.MemberInit(newExpr, bindings);
var lambda = Expression.Lambda<Func<Parent, dynamic>>(body, xParam);
var t = q.Select(lambda);
(2 used methods are here:)
public static Type GetDynamicType2(Dictionary<string, Type> fields)
{
if (null == fields)
throw new ArgumentNullException("fields");
if (0 == fields.Count)
throw new ArgumentOutOfRangeException("fields", "fields must have at least 1 field definition");
try
{
Monitor.Enter(builtTypes);
string className = "MyDynamicType";
if (builtTypes.ContainsKey(className))
return builtTypes[className];
TypeBuilder typeBuilder = moduleBuilder.DefineType(className,
TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Serializable);
foreach (var field in fields)
typeBuilder.DefineField(field.Key, field.Value, FieldAttributes.Public);
builtTypes[className] = typeBuilder.CreateType();
return builtTypes[className];
}
catch (Exception ex)
{
}
finally
{
Monitor.Exit(builtTypes);
}
return null;
}
public static Type GetDynamicType(IEnumerable<PropertyInfo> fields)
{
return GetDynamicType(fields.ToDictionary(f => f.Name, f => f.PropertyType));
}
But still I can't get internal properties of MyChild property of Parent.
How to do that?
Since nobody answered my question I tried many different ways to solve it, upshot problem solved utilizing recursive creation of Expression.
For every property of type Class (like MyChild in the question) we most create an Expression. Creation of Expressions most be recursive like this:
private Expression BuildExpression(Expression parentExpression,
Type parentPropertyType, string pathOfChildProperty)
{
string remainPathOfChild;
var childPropertyName =
GetFirstPropertyNameFromPathAndRemainPath(pathOfChildProperty, out remainPathOfChild);
if (string.IsNullOrEmpty(childPropertyName)) return parentExpression;
var childPropInfo = parentPropertyType.GetProperty(childPropertyName);
var childExpression = Expression.Property(parentExpression, childPropInfo);
return !string.IsNullOrEmpty(remainPathOfChild)
? BuildExpressionForInternalProperty(childExpression, childPropInfo.PropertyType, remainPathOfChild)
: childExpression;
}
private string GetFirstPropertyNameFromPathAndRemainPath(string path, out string remainPath)
{
if (string.IsNullOrEmpty(path))
{
remainPath = null;
return null;
}
var indexOfDot = path.IndexOf('.');
if (indexOfDot < 0)
{
remainPath = null;
return path;
}
remainPath = path.Substring(indexOfDot + 1);
return path.Substring(0, indexOfDot);
}
}
Recursive call will stop when remain path of internal property be empty.
In highest level the calling of this method is like this:
var inputParameter = Expression.Parameter(typeof(GrandParent), "x");
var expChildProperty =
BuildExpression(inputParameter,typeof(Parent),"Parent.MyChils.Name");
Finally result expression for above problem is (($x.Parent).MyChils).Name in debug view.
When creating a new item; is there any way to access all the field values that are set.
Since I'm using Entity.GetModifiedMembers() method to access the values of the fields that are changed when updating for logging purposes, the purpose is to have the equivalent result through an entity when creating, like a method Entity.GetSetMembers().
So in general, all I need is a key-value pair with "member name" and "value" items.
Example:
public class SomethingEntity
{
public int Id {get;set;}
public string Name {get;set;}
public DateTime Created {get;set;}
public DateTime Modified {get;set;}
}
public Dictionary<string, string> GetFieldsAndValuesOfCreatedItem(object entity)
{
//This is what I need, that can take all the objects from an entity and give
//the property-value pairs for the object instance
return RequieredMethod(entity);
}
public ExampleMethod()
{
var newObject = new SomethingEntity() { Name = "SomeName", Created = DateTime.Now };
Entity.insetOnSubmit(newObject);
Entity.SubmitChanges();
var resultList = GetFieldsAndValuesOfCreatedItem(newObject);
foreach (var propertyKeyValue in resultList)
{
var propertyString = "Property Name: " + propertyKeyValue.Key;
var valueString = "Value : " + propertyKeyValue.Value;
}
}
I've found out that, Reflection is the answer for that as far as I could find: so here is the method I've come up with:
public static Dictionary<string, string> GetFieldsAndValuesOfCreatedItem(object item)
{
var propertyInfoList = item.GetType().GetProperties(BindingFlags.DeclaredOnly |
BindingFlags.Public |
BindingFlags.Instance);
var list = new Dictionary<string, string>();
foreach (var propertyInfo in propertyInfoList)
{
var valueObject = propertyInfo.GetValue(item, null);
var value = valueObject != null ? valueObject.ToString() : string.Empty;
if (!string.IsNullOrEmpty(value))
{
list.Add(propertyInfo.Name, value);
}
}
return list;
}
What the best way convert this dictionary:
Dictionary<string, object> person = new Dictionary<string, object>();
person.Add("ID", 1);
person.Add("Name", "Alex");
to object:
public class Person
{
public int ID{get;set;}
public string Name{get;set;}
}
?
Here is my suggestion:
var newPerson = new Person
{
ID = (int)person["ID"],
Name = person["Name"].ToString()
};
This has no error handling and is assuming that the fields exists in the dictionary and are filled with valid values!
If you want to be able to do this for any object in general, you could use reflection. Assuming the values in the dictionary are the appropriate type and requires no conversion:
static T GetObject<T>(Dictionary<string, object> dict)
where T : new()
{
var obj = new T();
foreach (var property in typeof(T).GetProperties())
{
var args = new object[1];
var setter = property.GetSetMethod(); // property has a public setter
if (setter != null && dict.TryGetValue(property.Name, out args[0]))
setter.Invoke(obj, args);
}
return obj;
}
Then to use it:
var alexDict = new Dictionary<string, object>
{
{ "ID", 1 },
{ "Name", "Alex" },
};
var alexPerson = GetObject<Person>(alexDict);
Person myPerson = new Person();
myPerson.ID = (int)person["ID"];
myPerson.Name = (string)person["Name"];
Provides no error checking with the int cast.
The easy way:
var person = new Person
{
Id = (int)dict["ID"],
Name = (string)dict["Name"]
}
The generic way: use reflection.