Dynamically Getting Property Value From Class - c#

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");
}
}

Related

Extension method to remove not primitive property of an object

I'd like an extension method to create an object based on another but keep only the primitive properties. This object will be dumped into a log file in JSON format for logging.
Based on the classes shown below, in this sample, the created object should keep only these properties :
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
I am using .NET Framework 4.7
How can I do this?
// To use like this
var order = new Order();
var forLog = order.RemovePrimitives();
// Sample of classes
public class Order
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public List<Item> Items { get; set; }
public Address Address { get; set; }
}
public class Item{}
public class Address{}
public static class Extensions
{
public static string RemovePrimitives(this object obj)
{
// I need to create an anonymous, named 'TheNewObjectHere' object but only with primitives
// I will dump the object to push to a log file. I need only primitives
return JsonConvert.SerializeObject(TheNewObjectHere, Formatting.Indented);
}
}
Thanks
try this
public static class Extensions
{
public static string RemovePrimitives(this object obj)
{
var jsonObj = JObject.FromObject(obj);
var propToRemove = jsonObj.Properties().Where(i => !i.Value.GetType().ToString()
.Contains("JValue")).ToList();
foreach (var prop in propToRemove) prop.Remove();
return jsonObj.ToString();
}
}
You can use reflection to get primitive properties and then use JObject to build a JSON object dynamically.
public static readonly Type[] AdditionalPrimities = new[] { typeof(decimal), typeof(string) };
public static string RemovePrimitives<T>(this T obj)
{
var jObj = new JObject();
var props = GetPrimitiveProperties(obj);
foreach (var item in props)
{
var value = item.GetValue(obj);
if (value != null)
{
jObj.Add(item.Name, new JValue(value));
}
}
return jObj.ToString(Newtonsoft.Json.Formatting.Indented);
}
public static PropertyInfo[] GetPrimitiveProperties<T>()
{
var properties = typeof(T)
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(r => r.PropertyType.IsPrimitive || (r.PropertyType.IsGenericType && Nullable.GetUnderlyingType(r.PropertyType) != null) || AdditionalPrimities.Contains(r.PropertyType))
.Select(r => r)
.ToArray();
return properties;
}
public static void Main()
{
var order = new Order { FirstName = "abc", LastName = "cde", Address = new Address(), Age2 = 3, Age = 1 };
var final = order.RemovePrimitives();
Console.WriteLine(final);
}
Fiddle

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

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;

Ignore properties of class by comparing with a list in c#

I have a list where TestClass is a class with some predefined properties. So when i get data and bind my list with data i need to ignore some properties of TestClass by comparing it with a list. How can i achieve that?
Below is my code
public class TestClass
{
public int id{get;set;}
public string fname{get;set;}
public string lname{get;set;}
public string job {get;set;}
public string role{get;set;}
public string address{get;set;}
}
List<TestClass> ulist = null;
ulist = ToList<TestClass>(usersdataset.tables[0]); //fill my list with the data code is given below
so after getting the data into the list i need to remove some properties by comparing it with list of properties which should be returned.for example if my filteredlist should only show id,fname,role then i need to remove the extra properties from my ulist. so after the filter ulist should only contain id,fname and role
ToList Method
public static List<T> ToList<T>(DataTable dataTable) where T : new()
{
var dataList = new List<T>();
//Define what attributes to be read from the class
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
//Read Attribute Names and Types
var objFieldNames = typeof(T).GetProperties(flags).Cast<PropertyInfo>().
Select(item => new
{
Name = item.Name,
Type = Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType
}).ToList();
//Read Datatable column names and types
var dtlFieldNames = dataTable.Columns.Cast<DataColumn>().
Select(item => new {
Name = item.ColumnName,
Type = item.DataType
}).ToList();
foreach (DataRow dataRow in dataTable.AsEnumerable().ToList())
{
var classObj = new T();
foreach (var dtField in dtlFieldNames)
{
PropertyInfo propertyInfos = classObj.GetType().GetProperty(dtField.Name);
var field = objFieldNames.Find(x => x.Name == dtField.Name);
//var field = filteredColumns.Find(x => x.PropertyName == dtField.Name);
if (field != null)
{
if (dataRow[dtField.Name] != DBNull.Value)
propertyInfos.SetValue(classObj, dataRow[dtField.Name], null);
}
}
dataList.Add(classObj);
}
return dataList;
}
Use the overvride function Equals:
This sample compare only the id property
public class TestClass
{
public int id { get; set; }
public string fname { get; set; }
public string lname { get; set; }
public string job { get; set; }
public string role { get; set; }
public string address { get; set; }
public override bool Equals(object obj)
{
if (obj.GetType().Name != this.GetType().Name)
{
return false;
}
TestClass testclassObject = (TestClass)obj;
if (testclassObject.id != this.id)
{
return false;
}
return true;
}

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.
}

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