I have a class contains set of properties, one of the properties is a class type
as below :
public class ProgramData
{
public string code { get; set; }
public string message { get; set; }
public string program_id { get; set; }
public string email { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public GeneralSetup general_setup { get; set; }
}
public class GeneralSetup
{
public string store_name { get; set; }
public bool store_enabled { get; set; }
public bool promotions_enabled { get; set; }
public bool barcode_scan_enabled { get; set; }
public bool barcode_generate_enabled { get; set; }
}
i have a generic method [because i have set of classes] to validate the properties and i use reflection to get props name and value dynamically and its working fine, but the problem is when it validates general_setup property it gets its props and start validating them.
based on my business rules if it string.empty i want to set [code and message] props of the container class and i can not get this props at this level.
any ideas? thanks
public T ValidateObjectFields<T>(T entity) where T : class
{
Type objType = entity.GetType();
PropertyInfo[] properties = objType.GetProperties();
foreach (PropertyInfo property in properties)
{
object propValue = property.GetValue(entity, null);
var elems = propValue as IList;
if (elems != null)
{
foreach (var item in elems)
ValidateObjectFields(item);
}
else
{
// Check if current property has sub object
if (property.PropertyType.Assembly == objType.Assembly)
{
#region Validate Objects
var code = objType.GetProperty("code");
var mesg = objType.GetProperty("message");
// in this case the property has sub object and i want to get these properties of container class
if (code == null && mesg == null)
{
code = objType.GetProperty("code", BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public);
mesg = objType.GetProperty("message", BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public);
}
if (String.IsNullOrEmpty(Convert.ToString(propValue)))
{
//strDict = systemResponse.GetSystemResponse(Constants.structSystemResponses.Required_Field, //Constants.ConfigurableLanguages.English, Constants.enResponseSourceSystems.Webservice);
foreach (DictionaryEntry value in strDict)
{
code.SetValue(entity, Convert.ToString(value.Key), null);
mesg.SetValue(entity, Convert.ToString(value.Value) + " " + property.Name, null);
}
break;
}
#endregion
ValidateObjectFields(propValue);
}
else
{
#region Validate Objects
var code = objType.GetProperty("code");
var mesg = objType.GetProperty("message");
// in this case the property has sub object and i want to get these properties of container class
if(code == null && mesg == null)
{
PropertyInfo[] info = objType.BaseType.GetProperties(BindingFlags.Public);
code = objType.GetProperty("code", BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public);
mesg = objType.GetProperty("message", BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public);
}
if (String.IsNullOrEmpty(Convert.ToString(propValue)))
{
strDict = systemResponse.GetSystemResponse(Constants.structSystemResponses.Required_Field, Constants.ConfigurableLanguages.English, Constants.enResponseSourceSystems.Webservice);
foreach (DictionaryEntry value in strDict)
{
code.SetValue(entity, Convert.ToString(value.Key), null);
mesg.SetValue(entity, Convert.ToString(value.Value) + " " + property.Name, null);
}
break;
}
#endregion
}
}
}
return entity;
}
You can write an overload for the ValidateObjectFields which takes a parent element and this way you can access the properties of the containing class.
public TEntity ValidateObjectFields<TEntity>(TEntity entity, object Entity)
{
//Here put the code for handling the properties.
}
And in your code above call this method
foreach (var item in elems)
ValidateObjectFields(item,entity);
This will fix your problem I think.
Related
I have here my model:
public class RoleModel
{
public int ID { get; set; }
public string RoleName { get; set; }
public UserRoleModel TrackAndTrace { get; set; }
public UserRoleModel MailDelivery { get; set; }
public UserRoleModel MailAccounting { get; set; }
public UserRoleModel PerformanceMonitoring { get; set; }
public UserRoleModel AdminSettings { get; set; }
}
I want to get the value of any key of 'RoleModel'
public bool SaveRoleModule(RoleModel role)
{
PropertyInfo[] properties = typeof(RoleModel).GetProperties();
foreach (PropertyInfo property in properties)
{
if(property.Name != "ID" && property.Name != "RoleName")
{
Console.WriteLine(role[property.Name]);//(this doesn't work) I want it dynamic
Console.WriteLine(role.TrackAndTrace); //not like this
}
}
return true;
}
I used loop to shorten my code.
You can use this method here: Get property value from string using reflection in C# like this:
public bool SaveRoleModule(RoleModel role)
{
PropertyInfo[] properties = typeof(RoleModel).GetProperties();
foreach (PropertyInfo property in properties)
{
if(property.Name != "ID" && property.Name != "RoleName")
{
var value = GetPropValue(role, property.Name);
Console.WriteLine(value);//(this doesn't work) I want it dynamic
Console.WriteLine(role.TrackAndTrace); //not like this
}
}
return true;
}
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
You could try something like this:
public bool SaveRoleModule(RoleModel role)
{
PropertyInfo[] properties = typeof(RoleModel).GetProperties();
foreach (PropertyInfo property in properties)
{
if(property.Name != "ID" && property.Name != "RoleName")
{
Type t = role.GetType();
PropertyInfo p = t.GetProperty(property.Name);
UserRoleModel urm = ((UserRoleModel)p.GetValue(role, null));
// do something with urm
}
}
return true;
}
Though Fabio is right, this does seem strange and potentially based on faulty reasoning.
I trying to build a generic recursive function to iterate all properties / complex properties and return an array of all properties from the following structre:
public class Root
{
[FieldCodeItems(1, EnumFieldCode.INT, "ED", "0204")]
public int Prop1 { get; set; }
public Child Child { get; set; }
}
public class Child
{
[FieldCodeItems(1, EnumFieldCode.INT, "ED", "0208")]
public int PropChild1 { get; set; }
[FieldCodeItems(19, EnumFieldCode.ALPHANUMERIC, "ED", "0208")]
public string PropChild2 { get; set; }
public Child1 Child1 { get; set; }
}
public class Child1
{
[FieldCodeItems(1, EnumFieldCode.INT, "ED", "0211")]
public int PropChild3 { get; set; }
}
public class MyReturClass
{
public string FileCode { get; set; }
public string FieldCode { get; set; }
}
I can read all properties from Root class but I can't get the properties from the complex properties:
public static List<MyReturClass> GetItems<T>(T obj)
{
var ret = new List<MyReturClass>();
PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (PropertyInfo property in properties)
{
IEnumerable<Attribute> attributes = property.GetCustomAttributes();
foreach (Attribute attribute in attributes)
{
//here I read values from a custom property
var tr = (FieldCodeItems)attribute;
var value = obj.GetType().GetProperty(property.Name).GetValue(obj, null);
if (value == null) continue;
ret.Add(new MyReturClass
{
FieldCode = tr.FieldCode,
FileCode = tr.FileCode
});
}
//If is complex object (Child, Child1 etc)
if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
{
//I would like pass the complex property as parameter, but at this moment
//the property variable is a PropertyInfo and I need the complex type
//to get properties values from this object
GetItems(property); //Error. Also tried with GetItems(property.PropertyType);
}
}
return ret;
}
I would like pass the complex property as parameter, but at this moment the property variable is a PropertyInfo and I need the complex type to get properties values from this object.
How can I get this object?
I searched here, here and here but the solutions don't solve my problem.
Edit - 03-08-2018
Finally I found the awswer here
I added this code to solve the problem:
//If is complex object (Child, Child1 etc)
if (property.PropertyType.IsClass && property.PropertyType != typeof(string))
{
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(property.Name);
if (info == null) { return null; }
var v = info.GetValue(obj, null);
if (v != null)
GetItems(v);
}
have a look at https://learn.microsoft.com/en-us/dotnet/framework/reflection-and-codedom/how-to-examine-and-instantiate-generic-types-with-reflection
I am not sure if what you are looking for is going to work because in you EF you are configuring the classes as ComplexType. I am not sure the class itself knows its a complexType. You might end up creating a method on the DBcontext...
I used code from this post to implement feature toggles in an application and it is working great. However, now instead of my features being a straight bool on/off, each feature has two bool values: one for the general setting and one for the setting which is only applied to a subset of users. I've been trying to update the code to handle this and I'm finding my basic understanding of reflection and accessors is coming up short.
I'm using the code below to test in LINQPad - basically, compared to the post mentioned above, all I've done is tried to change TestFeatureToggle from a bool, to type MultiToggle but I'm struggling to Set or Get the value of the bool properties of the MultiToggle object. I get an exception at
return (bool)multiToggleProperty.GetValue(null,null);
"Non-static method requires a target". Which makes sense because the properties on MultiToggle are non-static. However, I don't have an instance of those objects and I don't understand how I would get one from a static class.
Any help would be really appreciated. My gut says it might not be possible!
void Main()
{
var exampleFeatureToggles = new List<FeatureToggle>
{
new FeatureToggle {Description = "Test", Id = 1, IsActive = true, Name = "TestFeatureToggle"}
};
FeatureToggles.SetFeatureToggles(exampleFeatureToggles);
Console.WriteLine(FeatureToggles.GetFeatureToggleSetting("TestFeatureToggle"));
}
public class FeatureToggle
{
public string Description { get; set; }
public int Id { get; set; }
public bool IsActive { get; set; }
public string Name { get; set; }
}
public class MultiToggle
{
public bool DefaultValue { get; private set; }
public bool OtherValue { get; private set; }
}
public static class FeatureToggles
{
//public static bool TestFeatureToggle { get; private set; }
public static MultiToggle TestFeatureToggle { get; private set; }
public static void SetFeatureToggles(List<FeatureToggle> toggles)
{
if (toggles == null) return;
var properties = typeof(FeatureToggles).GetProperties(BindingFlags.Public | BindingFlags.Static);
// All properties must be set to false to prevent a property staying true when deleted from the database
foreach (var property in properties)
{
var multiToggleProperties = typeof(MultiToggle).GetProperties();
foreach (var multiToggleProperty in multiToggleProperties)
{
multiToggleProperty.SetValue(new MultiToggle(), false, null);
}
}
foreach (var toggle in toggles)
{
foreach (var property in properties)
{
if (property.Name.ToLower() == toggle.Name.ToLower())
{
Type tProp = property.GetType();
var multiToggleProperties = typeof(MultiToggle).GetProperties();
foreach (var multiToggleProperty in multiToggleProperties)
{
Console.WriteLine(multiToggleProperty);
multiToggleProperty.SetValue(new MultiToggle(), toggle.IsActive, null);
}
}
}
}
}
public static bool GetFeatureToggleSetting(string propertyName)
{
var properties = typeof(FeatureToggles).GetProperties(BindingFlags.Public | BindingFlags.Static);
foreach (var property in properties)
{
if (property.Name.ToLower() == propertyName.ToLower())
{
Type tProp = property.GetType();
var multiToggleProperties = typeof(MultiToggle).GetProperties();
Console.WriteLine(multiToggleProperties);
foreach (var multiToggleProperty in multiToggleProperties)
{
Console.WriteLine(multiToggleProperty);
return (bool)multiToggleProperty.GetValue(null, null);
}
}
}
return false;
}
}
The idea was there but you've essentially "just overshot the mark". You are getting the "Non-static method requires a target" error because you are trying to get the value of a property in the value of a static property, without getting the value of the static property first (what a mouthful). i.e. you are going:
get static property type -> get instance property type -> get value of property from static property.
DefaultValue, and OtherValue are instance properties so you will need the instance object first before you can get their value. I made a few tweaks just to show you how to both set the static property and get the values from the static property. You should be able to tweak it from there:
void Main()
{
var exampleFeatureToggles = new List<FeatureToggle>
{
new FeatureToggle {Description = "Test", Id = 1, IsActive = true, Name = "TestFeatureToggle"}
};
FeatureToggles.SetFeatureToggles(exampleFeatureToggles);
Console.WriteLine(FeatureToggles.GetFeatureToggleSetting("TestFeatureToggle"));
}
public class FeatureToggle
{
public string Description { get; set; }
public int Id { get; set; }
public bool IsActive { get; set; }
public string Name { get; set; }
}
public class MultiToggle
{
public bool DefaultValue { get; private set; }
public bool OtherValue { get; private set; }
}
public static class FeatureToggles
{
//public static bool TestFeatureToggle { get; private set; }
public static MultiToggle TestFeatureToggle { get; private set; }
public static void SetFeatureToggles(List<FeatureToggle> toggles)
{
if (toggles == null) return;
var properties = typeof(FeatureToggles).GetProperties(BindingFlags.Public | BindingFlags.Static);
// All properties must be set to false to prevent a property staying true when deleted from the database
foreach (var property in properties)
{
// first change: set the _property_, not multiToggleProperty
property.SetValue(null, new MultiToggle());
}
foreach (var toggle in toggles)
{
foreach (var property in properties)
{
if (property.Name.ToLower() == toggle.Name.ToLower())
{
Type tProp = property.GetType();
var multiToggleProperties = typeof(MultiToggle).GetProperties();
// second change: create a nee instance, set the values, then set that value on the static property
var newMultiToggle = new MultiToggle();
property.SetValue(null, newMultiToggle);
foreach (var multiToggleProperty in multiToggleProperties)
{
Console.WriteLine(multiToggleProperty);
multiToggleProperty.SetValue(newMultiToggle, toggle.IsActive, null);
}
}
}
}
}
public static bool GetFeatureToggleSetting(string propertyName)
{
var properties = typeof(FeatureToggles).GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
foreach (var property in properties)
{
if (property.Name.ToLower() == propertyName.ToLower())
{
Type tProp = property.GetType();
// third change: get the static value first, then get the value from the properties on that instance.
var value = property.GetValue(null);
var multiToggleProperties = typeof(MultiToggle).GetProperties();
Console.WriteLine(multiToggleProperties);
foreach (var multiToggleProperty in multiToggleProperties)
{
Console.WriteLine(multiToggleProperty);
return (bool)multiToggleProperty.GetValue(value, null); //
}
}
}
return false;
}
}
I have a set of classes that are generated via xsd.exe based on *.xsd files. Each set of classes generated for each set of *.xsd files are almost the same, except that there are a few properties different in each class. For example, in both set 1 and set 2, Shape class might have different property.
I want to use a method to read the value of specified properties (UPDATE) of all classes in one set at a time (Update). There could be many levels of class. The method (e.g. GetProperty method) should only know about its parameter type, and the string representation of all properties. The method only read property.
Is there a better way of doing this:
internal class DynPropertyTest
{
public static void Set1Test()
{
Shape shape = new Shape()
{
Name = "Shape",
Shape2 = new Shape2()
{
Name = "Shape2",
Shape3 = new Shape3() { Name = "Shape3" }
}
};
GetProperty(shape);
}
public static void Set2Test() {
...
}
UPDATE
I would like to know an alternative way to achieve the similar function to the the method below
//Should store all properties value in a collection, rather than display it
//And somehow store/know the type of the property.
public static void GetProperty(ShapeBase shape)
{
//shape.Name
Console.WriteLine(shape.GetType().GetProperty("Name").GetValue(shape, null));
//Shape.Shape2
object shape2 = shape.GetType().GetProperty("Shape2").GetValue(shape, null);
Console.WriteLine(shape2);
//Shape.Shape2.Name
object shape2Name = shape.GetType().GetProperty("Shape2").PropertyType.GetProperty("Name")
.GetValue(shape2, null);
Console.WriteLine(shape2Name);
//shape.shape2.shape3
object shape3 = shape2.GetType().GetProperty("Shape3").GetValue(shape2, null);
Console.WriteLine(shape3);
//shape.shape2.shape3.Name
object shape3Name = shape2.GetType().GetProperty("Shape3").PropertyType.GetProperty("Name")
.GetValue(shape3, null);
Console.WriteLine(shape3Name);
}
}
abstract class ShapeBase { }
//Example only.
namespace Set1
{
class Shape : ShapeBase
{
public string Name { get; set; }
public Shape2 Shape2 { get; set; }
}
class Shape2
{
public string Name { get; set; }
public Shape3 Shape3 { get; set; }
}
class Shape3
{
public string Name { get; set; }
}
}
namespace Set2
{
class Shape : ShapeBase{}
...
}
This is how we implement this functionality (this is for getting a String value for dynamic SQL, but you should be able to apply it to your situation:
public static string GetFieldValueForSQL(object oRecord, string sName)
{
PropertyInfo theProperty = null;
FieldInfo theField = null;
System.Type oType = null;
try
{
oType = oRecord.GetType();
// See if the column is a property in the record
theProperty = oType.GetProperty(sName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public, null, null, new Type[0], null);
if (theProperty == null)
{
theField = oType.GetField(sName, BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public);
if (theField != null)
{
return theField.GetValue(oRecord).ToString();
}
}
else
{
return theProperty.GetValue(oRecord, null).ToString();
}
}
catch (Exception theException)
{
// Do something with the exception
return string.empty;
}
}
Update
To process all of the properties, you can use code similar to this (note that this does not take into account IEnumerable implementors, but that should be fairly straightforward):
public static void GetAllProperties(object oRecord)
{
System.Type oType = null;
try
{
oType = oRecord.GetType();
PropertyInfo[] cProperties;
cProperties = oType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo theProperty in cProperties)
{
if (theProperty.PropertyType.IsClass)
{
GetAllProperties(theProperty.GetValue(oRecord, null));
}
else
{
// use theProperty.GetValue(oRecord, null).ToString();
}
}
}
catch (Exception theException)
{
// Do something with the exception
}
}
My code can see the non-public members, but not the public ones. Why?
FieldInfo[] publicFieldInfos =
t.GetFields(BindingFlags.Instance | BindingFlags.Public);
is returning nothing.
Note: I'm trying to get at the properties on the abstract class as well as
the concrete class. (And read the attributes as well).
The MSDN example works with the 2 flags (BindingFlags.Instance | BindingFlags.Public) but my mini inheritance example below does not.
private void RunTest1()
{
try
{
textBox1.Text = string.Empty;
Type t = typeof(MyInheritedClass);
//Look at the BindingFlags *** NonPublic ***
int fieldCount = 0;
while (null != t)
{
fieldCount += t.GetFields(BindingFlags.Instance |
BindingFlags.NonPublic).Length;
FieldInfo[] nonPublicFieldInfos = t.GetFields(BindingFlags.Instance |
BindingFlags.NonPublic);
foreach (FieldInfo field in nonPublicFieldInfos)
{
if (null != field)
{
Console.WriteLine(field.Name);
}
}
t = t.BaseType;
}
Console.WriteLine("\n\r------------------\n\r");
//Look at the BindingFlags *** Public ***
t = typeof(MyInheritedClass);
FieldInfo[] publicFieldInfos = t.GetFields(BindingFlags.Instance |
BindingFlags.Public);
foreach (FieldInfo field in publicFieldInfos)
{
if (null != field)
{
Console.WriteLine(field.Name);
object[] attributes = field.GetCustomAttributes(t, true);
if (attributes != null && attributes.Length > 0)
{
foreach (Attribute att in attributes)
{
Console.WriteLine(att.GetType().Name);
}
}
}
}
}
catch (Exception ex)
{
ReportException(ex);
}
}
private void ReportException(Exception ex)
{
Exception innerException = ex;
while (innerException != null)
{
Console.WriteLine(innerException.Message + System.Environment.NewLine +
innerException.StackTrace + System.Environment.NewLine +
System.Environment.NewLine);
innerException = innerException.InnerException;
}
}
public abstract class MySuperType
{
public MySuperType(string st)
{
this.STString = st;
}
public string STString
{
get;
set;
}
public abstract string MyAbstractString { get; set; }
}
public class MyInheritedClass : MySuperType
{
public MyInheritedClass(string ic)
: base(ic)
{
this.ICString = ic;
}
[Description("This is an important property"), Category("HowImportant")]
public string ICString
{
get;
set;
}
private string _oldSchoolPropertyString = string.Empty;
public string OldSchoolPropertyString
{
get { return _oldSchoolPropertyString; }
set { _oldSchoolPropertyString = value; }
}
[Description("This is a not so importarnt property"),
Category("HowImportant")]
public override string MyAbstractString
{
get;
set;
}
}
EDIT
Here is my code after I took the advice given here:
private void RunTest1()
{
try
{
textBox1.Text = string.Empty;
Type t = typeof(MyInheritedClass);
//Look at the BindingFlags *** NonPublic ***
int fieldCount = 0;
while (null != t)
{
fieldCount += t.GetFields(BindingFlags.Instance | BindingFlags.NonPublic).Length;
PropertyInfo[] nonPublicFieldInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic);
foreach (PropertyInfo field in nonPublicFieldInfos)
{
if (null != field)
{
Console.WriteLine(field.Name);
}
}
t = t.BaseType;
}
Console.WriteLine("\n\r------------------\n\r");
//Look at the BindingFlags *** Public ***
t = typeof(MyInheritedClass);
PropertyInfo[] publicFieldInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (PropertyInfo field in publicFieldInfos)
{
if (null != field)
{
Console.WriteLine(field.Name);
textBox1.Text += field.Name + System.Environment.NewLine;
DescriptionAttribute[] attributes = (DescriptionAttribute[])field.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
foreach (Attribute att in attributes)
{
Console.WriteLine(att.GetType().Name);
}
}
}
}
}
catch (Exception ex)
{
ReportException(ex);
}
}
private void ReportException(Exception ex)
{
Exception innerException = ex;
while (innerException != null)
{
Console.WriteLine(innerException.Message + System.Environment.NewLine + innerException.StackTrace + System.Environment.NewLine + System.Environment.NewLine);
}
}
public abstract class MySuperType
{
public MySuperType(string st)
{
this.STString = st;
}
public string STString
{
get;
set;
}
public abstract string MyAbstractString {get;set;}
}
public class MyInheritedClass : MySuperType
{
public MyInheritedClass(string ic)
: base(ic)
{
this.ICString = ic;
}
[Description("This is an important property"),Category("HowImportant")]
public string ICString
{
get;
set;
}
private string _oldSchoolPropertyString = string.Empty;
public string OldSchoolPropertyString
{
get { return _oldSchoolPropertyString; }
set { _oldSchoolPropertyString = value; }
}
[Description("This is a not so importarnt property"), Category("HowImportant")]
public override string MyAbstractString
{
get; set;
}
}
Maybe because you're using GetFields and the class doesn't have any public fields: properties and fields are two different things.
Try using the GetProperties method instead of GetFields.
Generally you're not going to find any non-public fields. Assuming your typical class is structured something like this:
public class MyClass {
private int myField;
public int MyProperty {
get { return myField; }
}
}
Notice the field (myField) is private whereas the property (MyProperty) is public.
So to find fields, you'll probably get the most mileage out of:
// note: fields -> generally non-public
Type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)
Whereas for properties the reverse is true: you're likely to get the most mileage out of:
// note: properties -> generally public
Type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
Obviously, if you want to find all (public and non-public) members of a particular kind (field/property), you're going to have to use:
Type.GetFields( // (or GetProperties)
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
)