How to get/set value of properties using string property paths? - c#

Let's say we have a class Root that has BasicDetails class property and then basicDetails has two properties. A string "Name" and a dynamic object called "CustomAttributes".
I want to get the value in the following manner:
var root = new Root();
root.BasicDetails.Name = "Samurai";
root.BasicDetails.CustomAttributes.phone = "12345";
string res1 = GetDeepPropertyValue(root, "BasicDetails.CustomAttributes.Phone").ToString();
string res2 = GetDeepPropertyValue(root, "BasicDetails.Name").ToString();
The following is the code I have tried (based on another answer on SO):
public static object GetDeepPropertyValue(object src, string propName)
{
if (propName.Contains('.'))
{
string[] Split = propName.Split('.');
string RemainingProperty = propName.Substring(propName.IndexOf('.') + 1);
return GetDeepPropertyValue(src.GetType().GetProperty(Split[0]).GetValue(src, null), RemainingProperty);
}
else
return src.GetType().GetProperty(propName).GetValue(src, null);
}
The following are the classes:
public class Root
{
public Root()
{
BasicDetails = new BasicDetails();
}
public BasicDetails BasicDetails { get;set;}
}
public class BasicDetails
{
public BasicDetails()
{
CustomAttributes = new ExpandoObject();
}
public string Name { get; set; }
public dynamic CustomAttributes { get; set; }
}
The function that I have tried is throwing null reference error. Unfortunately I do not understand reflection too well so at the moment I am monkey patching. If someone could please explain c#how this can be done it would be great. Thank you in advance.

Following method gets values from nested properties:
public static object GetPropertyValue(object src, string propName)
{
if (src == null) throw new ArgumentException("Value cannot be null.", "src");
if (propName == null) throw new ArgumentException("Value cannot be null.", "propName");
if (propName.Contains("."))//complex type nested
{
var temp = propName.Split(new char[] { '.' }, 2);
return GetPropertyValue(GetPropertyValue(src, temp[0]), temp[1]);
}
else
{
if (src is ExpandoObject)
{
var expando = src as IDictionary<string, object>;
if (expando != null)
{
object obj;
expando.TryGetValue(propName, out obj);
return obj;
}
return null;
}
else
{
var prop = src.GetType().GetProperty(propName);
return prop != null ? prop.GetValue(src, null) : null;
}
}
}
Usage:
string res1 = GetPropertyValue(root, "BasicDetails.CustomAttributes.phone") as string;
string res2 = GetPropertyValue(root, "BasicDetails.Name") as string;

Related

C# recursively check all values not null

Without wanting to reinvent the wheel, is there a .NET NuGet library to perform checks on a object recursively for argument checking?
If not, how would I convert the code to check if a property is null, and if a type that can hold properties of its own, recursively check that type, and end up with a list of property names that are null.
public static class Assert
{
public static void AllPropertiesNotNull<T>(T obj)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
var emptyProperties = typeof(T)
.GetProperties()
.Select(prop => new { Prop = prop, Val = prop.GetValue(obj, null) })
.Where(val => IsEmpty((dynamic)val.Val))
.Select(val => val.Prop.Name)
.ToList();
if (emptyProperties.Count > 0)
throw new ArgumentNullException(emptyProperties.First());
}
private static bool IsEmpty(object o) { return o == null; }
}
Note: You should do null checking on constructor parameters or method parameters and throw exception when the parameter is unexpectedly null. It's better to follow the common best practices.
Anyway, here is an example showing how you can check all properties of an object recursively using an extension method and throw exception of finding null properties...
You can create an extension method ThrowOnNullProperty for object and use it like this:
something.ThrowOnNullProperty();
Here is an implementation of such extension method:
If the passed object is null, throw exception.
If the object is a primitive type or a string, continue.
If the object has been visited before, then continue, otherwise add it to list of visited objects.
Check first level properties of the object and if there are null properties, throw an exception containing name of the null properties.
If the first level properties are not null, the for each property value go to 1.
Here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
public static class ObjectExtensions
{
public static void ThrowOnNullProperty(this object obj)
{
ThrowOnNullProperty(obj, new HashSet<object>());
}
private static void ThrowOnNullProperty(object obj, HashSet<object> visitedObjects)
{
if (obj == null)
throw new ArgumentNullException(nameof(obj));
if (obj.GetType().IsPrimitive || obj.GetType() == typeof(string))
return;
if (visitedObjects.Contains(obj))
return;
visitedObjects.Add(obj);
var nullPropertyNames = obj.GetType().GetProperties()
.Where(p => p.GetValue(obj) == null)
.Select(p => p.Name);
if (nullPropertyNames.Any())
throw new ArgumentException(
$"Null properties: {string.Join(",", nullPropertyNames)}");
var notNullPropertyValues = obj.GetType().GetProperties()
.Select(p => p.GetValue(obj))
.Where(v => v != null);
foreach (var item in notNullPropertyValues)
ThrowOnNullProperty(item, visitedObjects);
}
}
To do so, write a method to check the properties of current object and call it recursively on the non-null properties. I went ahead and wrote some code, which includes looping over dictionaries and enumerables and checking them for nulls also, taking into account circular references as mentioned by #dcg.
static readonly HashSet<Type> excludedTypes = new HashSet<Type>{ typeof(string) };
public static List<string> AllPropertiesNotNull(IDictionary dictionary, string name, HashSet<object> alreadyChecked)
{
List<string> nullValues = new List<string>();
foreach(object key in dictionary.Keys)
{
object obj = dictionary[key];
if (!alreadyChecked.Contains(obj))
{
string elementName = $"{name}[\"{key}\"]";
nullValues.AddRange(AllPropertiesNotNull(obj, elementName, alreadyChecked));
}
}
return nullValues;
}
public static List<string> AllPropertiesNotNull(IEnumerable enumerable, string name, HashSet<object> alreadyChecked)
{
List<string> nullValues = new List<string>();
int i = 0;
foreach (object obj in enumerable)
{
if (!alreadyChecked.Contains(obj))
{
string elementName = $"{name}[{i}]";
nullValues.AddRange(AllPropertiesNotNull(obj, elementName, alreadyChecked));
}
i++;
}
return nullValues;
}
public static List<string> AllPropertiesNotNull(object obj, string name, HashSet<object> alreadyChecked, string baseName = "")
{
List<string> nullValues = new List<string>();
string basePropertyName;
if (string.IsNullOrEmpty(baseName))
{
basePropertyName = name;
}
else
{
basePropertyName = baseName + "." + name;
}
if (obj == null)
{
nullValues.Add(basePropertyName);
}
else if (!alreadyChecked.Contains(obj))
{
alreadyChecked.Add(obj);
if (!excludedTypes.Contains(obj.GetType()))
{
foreach (PropertyInfo property in obj.GetType().GetProperties())
{
object value = property.GetValue(obj);
string propertyName = basePropertyName + "." + property.Name;
if (value == null)
{
nullValues.Add(propertyName);
}
else
{
if (typeof(IDictionary).IsAssignableFrom(property.PropertyType))
{
nullValues.AddRange(AllPropertiesNotNull((IDictionary)value, propertyName, alreadyChecked));
}
else if (typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
{
nullValues.AddRange(AllPropertiesNotNull((IEnumerable)value, propertyName, alreadyChecked));
}
else
{
nullValues.AddRange(AllPropertiesNotNull(value, property.Name, alreadyChecked, basePropertyName));
}
}
}
}
}
return nullValues;
}
I wrote some classes to test with:
class A
{
public string s1 { set; get; }
public string s2 { set; get; }
public int i1 { set; get; }
public int? i2 { set; get; }
public B b1 { set; get; }
public B b2 { set; get; }
}
class B
{
public string s1 { set; get; }
public string s2 { set; get; }
public int i1 { set; get; }
public int? i2 { set; get; }
public A a1 { set; get; }
public Dictionary<int, string> d1 { set; get; }
public List<A> l1 { set; get; }
}
and tested it as follows:
A a = new A
{
s1 = "someText"
};
B b = new B
{
s1 = "someText",
a1 = a,
d1 = new Dictionary<int, string>
{
{ 1, "someText" },
{ 2, null }
},
l1 = new List<A>{ null, new A { s1 = "someText" } , a }
};
a.b1 = b;
Console.WriteLine(string.Join("\n", AllPropertiesNotNull(a, nameof(a), new HashSet<object>())));
Output:
a.s2
a.i2
a.b1.s2
a.b1.i2
a.b1.d1["2"]
a.b1.l1[0]
a.b1.l1[1].s2
a.b1.l1[1].i2
a.b1.l1[1].b1
a.b1.l1[1].b2
a.b2
Few points to take note of:
Only public properties are considered, use BindingFlags if you want to consider non-public ones.
Some types might need to be individually considered (e.g.: string) or maybe not (depending on your own case).
As mentioned before, the code loops on dictionaries and enumerables and checks every value for them too. You might or might not want that (depending on your own case).

Converting Flat file to List which is a property of another class

public class DummyResponse
{
public int UpdatedRecords { get; set; }
public string Id { get; set; }
public bool Isvalid { get; set; }
}
public class Request
{
public List<DummyResponse> Changes { get; set; }
public string ReuestedBy { get; set; }
public Request()
{
Changes = new List<DummyResponse>();
}
}
I have a flat file which contains tab separated data for Dummy Response.
I want this to be serialized to Request object.
The implementation needs should be generic as in I only need user to pass T (Request) in this case and identify the correct sub type to be filled from flat file.
I have below Code to convert it into Object. How ever its only working for properties having string type.
interface ICollectionBuilder
{
object Build(IList dictionaries);
}
internal class CollectionBuilder<T> : ICollectionBuilder where T : new()
{
public object Build(IList dictionaries)
{
var dictConverter = new DictionaryConerter<T>();
return dictionaries
.OfType<IDictionary<string, object>>()
.Select(dict => dictConverter.ConvertTyped(dict))
.ToList();
}
}
interface IDictionaryConverter
{
object Convert(IDictionary<string, object> dict);
}
internal class DictionaryConerter<T> : IDictionaryConverter where T : new()
{
public object Convert(IDictionary<string, object> dict)
{
return ConvertTyped(dict);
}
public T ConvertTyped(IDictionary<string, object> dict)
{
T t = new T();
var properties = t.GetType().GetProperties();
foreach (KeyValuePair<string, object> curr in dict)
{
if (String.IsNullOrEmpty(curr.Key)) continue;
if (curr.Value == null) continue;
Type valType = null;
Type newType = null;
PropertyInfo currProperty = null;
foreach (PropertyInfo p in properties)
{
if (String.IsNullOrEmpty(p.Name)) continue;
if (String.Compare(p.Name.ToLower(), curr.Key.ToLower()) == 0)
{
valType = t.GetType().GetProperty(p.Name).PropertyType;
newType = Nullable.GetUnderlyingType(valType) ?? valType;
currProperty = p;
break;
}
}
object newVal = curr.Value;
var curDict = curr.Value as IDictionary<string, object>;
var curList = curr.Value as IList;
if (curDict != null && newType.GetConstructor(Type.EmptyTypes) != null)
{
newVal = ((IDictionaryConverter)Activator.CreateInstance(typeof(DictionaryConerter<>).MakeGenericType(newType))).Convert(curDict);
}
else if (
curList != null &&
curList.OfType<IDictionary<string, object>>().Any() &&
newType.IsGenericType &&
newType.GetGenericTypeDefinition() == typeof(List<>) &&
newType.GetGenericArguments()[0].GetConstructor(Type.EmptyTypes) != null)
{
newVal = ((ICollectionBuilder)Activator.CreateInstance(typeof(CollectionBuilder<>).MakeGenericType(newType.GetGenericArguments()[0]))).Build(curList);
}
t.GetType().GetProperty(currProperty.Name).SetValue(t, newVal);
}
return t;
}
}
Example usage:
void Main ()
{
var dict = new Dictionary<string,object>();
dict.Add("ReuestedBy",abc);
var innerDict = new Dictionary<string,object>();
var list = new LIst<Dictionary<string,object>>();
innerDict.Add("UpdatedRecords","45");
innerDict.Add("Id","1");
innerDict.Add("IsValid","False");
dict.Add("Changes",list )
}
The problem here is it not working for any other type other than string.
I fixed it using below code while setting value
propertyVal = Convert.ChangeType(propertyVal, targetType);
propertyInfo.SetValue(inputObject, propertyVal, null);

C#: Get the name of a property and check its value

I have the following class Franchise:
public class Franchise
{
public string FolderName { get; set; }
public string InstallerExeName { get; set; }
}
I have a method that checks specific property value for uniqness among all franchises in the db.
public bool ValidateFolderName(string folderName)
{
var allFranchises = _franchiseService.GetAll();
var result = allFranchises.Any(f => f.FolderName == folderName);
return result;
}
The problem is I have to check another property for uniqness:
public bool ValidateInstallerExeName(string installerExeName)
{
var allFranchises = _franchiseService.GetAll();
var result = allFranchises.Any(f => f.InstallerExeName == installerExeName);
return result;
}
I want to avoid code duplication by making a generic method. Something like:
public bool ValidateProperty(string propertyName)
{
var allFranchises = _franchiseService.GetAll();
// Not sure how to write this line
var result = allFranchises.Any(f => f.[propertyName] == propertyName);
return result;
}
The problem is I am not sure how to re-write this line of code so that it can get the property name and check its value by the provided parameter:
var result = allFranchises.Any(f => f.[propertyName] == propertyName);
I know I can do something like this with reflection:
franchise.GetType().GetProperty(propertyName).GetValue(franchise, null);
but I am not sure how can I make this to fit my case. Any help with working example will be greatly appreciated. Thanks!
Here is a full working example using reflection:
class Program
{
private static List<Franchise> allFranchises;
static void Main(string[] args)
{
allFranchises = new List<Franchise>
{
new Franchise() { FolderName=#"c:\1", InstallerExeName="1.exe" },
new Franchise() { FolderName=#"c:\2", InstallerExeName="2.exe" },
new Franchise() { FolderName=#"c:\3", InstallerExeName="3.exe" },
new Franchise() { FolderName=#"c:\4", InstallerExeName="4.exe" },
new Franchise() { FolderName=#"c:\5", InstallerExeName="5.exe" },
};
Console.WriteLine(ValidateProperty("FolderName", #"c:\2", allFranchises));
Console.WriteLine(ValidateProperty("InstallerExeName", "5.exe", allFranchises));
Console.WriteLine(ValidateProperty("FolderName", #"c:\7", allFranchises));
Console.WriteLine(ValidateProperty("InstallerExeName", "12.exe", allFranchises));
}
public static bool ValidateProperty(string propertyName, object propertyValue, IEnumerable<Franchise> validateAgainst)
{
PropertyInfo propertyInfo = typeof(Franchise).GetProperty(propertyName);
return validateAgainst.Any(f => propertyInfo.GetValue(f, null) == propertyValue);
}
}
public class Franchise
{
public string FolderName { get; set; }
public string InstallerExeName { get; set; }
}
It will print out:
True
True
False
False
as expected.
public bool ValidateProperty<TType, TPropertyType>(Func<TType, TPropertyType> propertySelector, TPropertyType propertyValue)
{
return _franchiseService.GetAll().Any(f => propertySelector(f) == propertyValue);
}
You can call it like this:
if( ValidateProperty(x => x.FirstName, "Joe") )
This does not use reflection and you have intellisense for your propertyname as well.
You may use an extension method:
public static bool ValidateProperty(
this IEnumerable<Franchise> franchises,
string property,
object value)
{
var prop = typeof(Franchise).GetProperty(property);
if (prop == null)
throw new ArgumentException("Property does not exist");
return franchises.Any(f =>
prop.GetValue(f) == value);
}
Use it like this:
var r = _franchiseService.GetAll().ValidateProperty("FolderName", "myfolder1");
You can build the function you want using System.Linq.Expressions
public class Franchise
{
public string FolderName { get; set; }
public string InstallerExeName { get; set; }
bool ValidateProperty(string propertyName) {
var allFranchises = new List<Franchise>();
var parameter = Expression.Parameter(typeof(Franchise));
var property = Expression.Property(parameter, propertyName);
var thisExpression = Expression.Constant(this, typeof(Franchise));
var value = Expression.Property(thisExpression, propertyName);
var notThis = Expression.ReferenceNotEqual(thisExpression, property);
var equal = Expression.Equal(value, property);
var lambda = Expression.Lambda<Func<Franchise, bool>>(Expression.And(notThis, equal));
// lamda is now the equivalent of:
// x => !object.ReferenceEquals(this, x) && object.Equals(x.Property, this.Property)
return allFranchises.Any(lambda.Compile());
}
}
If allFranchises is of type IQueryable you use allFranchises.Any(lambda)
You could also caches the expression for later use if you are worried about performance.
}

Dynamically Getting Property Value From Class

I have a class which i want to retrieve a property from it dynamically
here is a sample from the class
namespace TEST
{
public class Data
{
public string Username { get; set; }
public string Password { get; set; }
}
}
i am trying to use GetProperty but it always return null
static object PropertyGet(object p, string propName)
{
Type t = p.GetType();
PropertyInfo info = t.GetProperty(propName);
if (info == null)
return null;
return info.GetValue(propName);
}
like this
var data = new Data();
var x = PropertyGet(data, "Username");
Console.Write(x?? "NULL");
This line is wrong, and should be throwing an exception for you:
return info.GetValue(propName);
You need to pass in the object from which to extract the property, i.e.
return info.GetValue(p);
Also note that currently data.Username is null. You want something like:
var data = new Data { Username = "Fred" };
I've validated that with these two changes, it works.
This works:
public class Data
{
public string Username { get; set; }
public string Password { get; set; }
}
public class Program
{
static object PropertyGet(object p, string propName)
{
Type t = p.GetType();
PropertyInfo info = t.GetProperty(propName);
if (info == null)
{
return null;
}
else
{
return info.GetValue(p, null);
}
}
static void Main(string[] args)
{
var data = new Data() { Username = "Fred" };
var x = PropertyGet(data, "Username");
Console.Write(x ?? "NULL");
}
}

c# - How to iterate through classes fields and set properties

I am not sure if this is possible but I want to iterate through a class and set a field member property without referring to the field object explicitly:
public class Employee
{
public Person _person = new Person();
public void DynamicallySetPersonProperty()
{
MemberInfo[] members = this.GetType().GetMembers();
foreach (MemberInfo member in members.Where(a => a.Name == "_person"))
//get the _person field
{
Type type = member.GetType();
PropertyInfo prop = type.GetProperty("Name"); //good, this works, now to set a value for it
//this line does not work - the error is "property set method not found"
prop.SetValue(member, "new name", null);
}
}
}
public class Person
{
public string Name { get; set; }
}
In the answer that I marked as the answer you need to add:
public static bool IsNullOrEmpty(this string source)
{
return (source == null || source.Length > 0) ? true : false;
}
Here's a complete working example:
public class Person
{
public string Name { get; set; }
}
class Program
{
static void PropertySet(object p, string propName, object value)
{
Type t = p.GetType();
PropertyInfo info = t.GetProperty(propName);
if (info == null)
return;
if (!info.CanWrite)
return;
info.SetValue(p, value, null);
}
static void PropertySetLooping(object p, string propName, object value)
{
Type t = p.GetType();
foreach (PropertyInfo info in t.GetProperties())
{
if (info.Name == propName && info.CanWrite)
{
info.SetValue(p, value, null);
}
}
}
static void Main(string[] args)
{
Person p = new Person();
PropertySet(p, "Name", "Michael Ellis");
Console.WriteLine(p.Name);
PropertySetLooping(p, "Name", "Nigel Mellish");
Console.WriteLine(p.Name);
}
}
EDIT: added a looping variant so you could see how to loop through property info objects.
public class Person
{
public string Name { get; set; }
}
public class Employee
{
public Person person = new Person();
public void DynamicallySetPersonProperty()
{
var p = GetType().GetField("person").GetValue(this);
p.GetType().GetProperty("Name").SetValue(p, "new name", null);
}
}
With the following Extension methods that I have created, you can set or get any property value even if they are nested
GetPropertyValue(customObject, "Property.Nested.Child.Name");
or set
SetPropertyValue(customObject, "Property.Nested.Child.Name", "my custom name");
private class TargetProperty
{
public object Target { get; set; }
public PropertyInfo Property { get; set; }
public bool IsValid { get { return Target != null && Property != null; } }
}
private static TargetProperty GetTargetProperty(object source, string propertyName)
{
if (!propertyName.Contains("."))
return new TargetProperty { Target = source, Property = source.GetType().GetProperty(propertyName) };
string[] propertyPath = propertyName.Split('.');
var targetProperty = new TargetProperty();
targetProperty.Target = source;
targetProperty.Property = source.GetType().GetProperty(propertyPath[0]);
for (int propertyIndex = 1; propertyIndex < propertyPath.Length; propertyIndex++)
{
propertyName = propertyPath[propertyIndex];
if (!string.IsNullOrEmpty(propertyName))
{
targetProperty.Target = targetProperty.Property.GetValue(targetProperty.Target, null);
targetProperty.Property = targetProperty.Target.GetType().GetProperty(propertyName);
}
}
return targetProperty;
}
public static bool HasProperty(this object source, string propertyName)
{
return GetTargetProperty(source, propertyName).Property != null;
}
public static object GetPropertyValue(this object source, string propertyName)
{
var targetProperty = GetTargetProperty(source, propertyName);
if (targetProperty.IsValid)
{
return targetProperty.Property.GetValue(targetProperty.Target, null);
}
return null;
}
public static void SetPropertyValue(this object source, string propertyName, object value)
{
var targetProperty = GetTargetProperty(source, propertyName);
if(targetProperty.IsValid)
{
targetProperty.Property.SetValue(targetProperty.Target, value, null);
}
}
And here are a couple of tests for it
[TestFixture]
public class ObjectExtensionsTest
{
private class MockClass
{
public MockClass()
{
Nested = new NestedMockClass();
}
public string Id { get; set; }
public string Name { get; set; }
public string GetOnly { get { return "MockClass"; } }
public string SetOnly { set { } }
public NestedMockClass Nested { get; set; }
}
private class NestedMockClass
{
public string NestedId { get; set; }
public string NestedName { get; set; }
public string NestedGetOnly { get { return "NestedMockClass"; } }
public string NestedSetOnly { set { } }
}
[Test]
public void TestShouldFindProperty()
{
MockClass mockObject = new MockClass();
Assert.IsTrue(mockObject.HasProperty("Id"));
Assert.IsTrue(mockObject.HasProperty("Name"));
Assert.IsTrue(mockObject.HasProperty("GetOnly"));
Assert.IsTrue(mockObject.HasProperty("SetOnly"));
Assert.IsTrue(mockObject.HasProperty("Nested"));
Assert.IsTrue(mockObject.HasProperty("Nested.NestedId"));
Assert.IsTrue(mockObject.HasProperty("Nested.NestedName"));
Assert.IsTrue(mockObject.HasProperty("Nested.NestedGetOnly"));
Assert.IsTrue(mockObject.HasProperty("Nested.NestedSetOnly"));
}
[Test]
public void TestShouldGetPropertyValue()
{
MockClass mockObject = new MockClass();
mockObject.Id = "1";
mockObject.Name = "Name";
mockObject.Nested.NestedId = "NestedId";
mockObject.Nested.NestedName = "NestedName";
Assert.AreEqual(mockObject.Id, mockObject.GetPropertyValue("Id"));
Assert.AreEqual(mockObject.Name, mockObject.GetPropertyValue("Name"));
Assert.AreEqual(mockObject.GetOnly, mockObject.GetPropertyValue("GetOnly"));
Assert.AreEqual(mockObject.Nested.NestedId, mockObject.GetPropertyValue("Nested.NestedId"));
Assert.AreEqual(mockObject.Nested.NestedName, mockObject.GetPropertyValue("Nested.NestedName"));
}
[Test]
public void TestShouldSetPropertyValue()
{
MockClass mockObject = new MockClass();
mockObject.SetPropertyValue("Id", "1");
mockObject.SetPropertyValue("Name", "Name");
mockObject.SetPropertyValue("Nested.NestedId", "NestedId");
mockObject.SetPropertyValue("Nested.NestedName", "NestedName");
Assert.AreEqual(mockObject.Id, "1");
Assert.AreEqual(mockObject.Name, "Name");
Assert.AreEqual(mockObject.Nested.NestedId, "NestedId");
Assert.AreEqual(mockObject.Nested.NestedName, "NestedName");
}
}
Hope you find it useful.
You are trying to set the Name property of your Employee class's _person field. It doesn't have one. Try this:
prop.SetValue(((FieldInfo)member).GetValue(this), "new name", null)
Not sure if you need to cast the first argument like this:
prop.SetValue((Person)((FieldInfo)member).GetValue(this), "new name", null)
This then applies it to the value of the _person field instead.
You a trying to perform SetValue() on the property Name of the variable member that is a MemberInfo object and this proeprty is read only.
Note you do not need to iterate over all memebers and you do not need to get the field _person with reflection as it is defined in the same class as the method DynamicallySetPersonProperty().
So the code shoul read like this.
PropertyInfo property = this._person.GetType().GetProperty("Name");
property.SetValue(this._person, "new name", null);
The first line will fail if _person is null. So you can use reflectiopn to get the type of the field.
FieldInfo field = this.GetType().GetField("_person", BindingFlags.Public);
PropertyInfo property = field.FieldType.GetProperty("Name");
But now accessing this property will still fail if _personis null.
property.Setvalue(field.GetValue(this), "new name", null);
try this:
public static void ApplyPropertyChanges(this object objDest, object objToCopyFrom)
{
if (objDest == null)
throw new ArgumentNullException();
if (objToCopyFrom == null)
throw new ArgumentNullException("objToCopyFrom");
if (objDest.GetType() != objToCopyFrom.GetType())
throw new Exception("Invalid type. Required: \"" + objDest.GetType().ToString() + "\"");
foreach (System.Reflection.PropertyInfo piOrig in objDest.GetType().GetProperties())
{
object editedVal = objToCopyFrom.GetType().GetProperty(piOrig.Name).GetValue(objToCopyFrom, null);
piOrig.SetValue(objDest,
editedVal,
null);
}
}
usage example:
public ActionResult Edit(Team editedTeamData)
{
if (!ModelState.IsValid)
return View();
Team origTeam = (from t in _db.Teams
where t.TeamID == editedTeamData.TeamID
select t).FirstOrDefault();
origTeam.ApplyPropertyChanges(editedTeamData);
_db.SubmitChanges();
return RedirectToAction("Index");
}

Categories

Resources