class ClassA
{
public ClassB myProp {get;set;}
}
class ClassB
{
public ClassC anotherProp {get;set;}
}
class ClassC
{
public string Name {get;set;}
}
I have an object of the ClassA type. How, by the reflection iterate recursively to get ClassC's Name property value ?
I was a little sketchy on what you wanted to accomplish. I think you want to start with ClassA and eventually walk through the properties and get to ClassC. To do this you mostly have to understand how to do recursive programming and a small amount of knowledge of Reflection. Here is a modified version of code that I have used in the past, which you can find here.
private void SerializeObject(object obj) {
Type type = obj.GetType();
foreach (PropertyInfo info2 in type.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
{
MethodInfo getMethod = info2.GetGetMethod(true);
if (getMethod != null)
SerializeObject(getMethod.Invoke(obj, null));
}
}
What this does is walk through each property and uses the get method of each property to execute the property and get the object that is being returned so that you can walk through it by calling the same SerializeObject method.
Ok, solved.
Let's say that I have the path to the Property which value I wanna get:
ClassB.ClassC.Name
then, after splitting that parh I iterate through the tree without recursion ;)
var dataPath = column.SortMemberPath.Split(new char[] { '.' });
[...]
foreach (var item in (System.Collections.IList)myObject)
{
var newItem = item;
foreach (var path in dataPath)
{
var actalValue = newItem.GetType().GetProperty(path).GetValue(newItem, null);
newItem = actalValue; //it does the trick
}
now, the newItem is my wanted property value
}
Related
I want to get the value from a virtual property from a inherited class see my code below:
Base class:
public class TestBaseClass
{
public virtual int Index { get; }
}
Inherited class:
public class TestInheritedClass : TestBaseClass
{
public override int Index => 100; // I want to get this value using reflection
}
My Code:
static void Main(string[] args)
{
var assemblies = Assembly.LoadFile(args[0]);
foreach(var type in assembly.ExportedTypes)
{
if(type.IsSubclassOf(typeof(TestBaseClass))
{
foreach(var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)
{
var value = prop.GetValue(typeof(int), null); // I expect to return 100 from override Index value
}
}
}
}
Did I missed something or did I made this all wrong? I'm trying to get the value 100 from the virtual property. Is there a way to get the value?
Is there a way to get the value?
Yes, there is a way.
Let's first see what you've done there:
prop.GetValue(typeof(int), null)
You're using this overload of PropertyInfo.GetValue. It expects the instance of the object from which to get the value as first parameter. Instead, you're passing typeof(int). That's not an instance of TestInheritedClass.
I will ignore the second parameter here, because we're not talking about an indexer.
You can read about that parameter in the documentation.
Instead you must create an instance of TestInheritedClass first:
var instance = Activator.CreateInstance(typeof(TestInheritedClass));
Then use it like this:
if (type.IsSubclassOf(typeof(TestBaseClass))
{
var instance = Activator.CreateInstance(type);
foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
{
var value = prop.GetValue(instance);
}
}
I need to get a list of properties from Class T - GetProperty<Foo>(). I tried the following code but it fails.
Sample Class:
public class Foo {
public int PropA { get; set; }
public string PropB { get; set; }
}
I tried the following Code:
public List<string> GetProperty<T>() where T : class {
List<string> propList = new List<string>();
// get all public static properties of MyClass type
PropertyInfo[] propertyInfos;
propertyInfos = typeof(T).GetProperties(BindingFlags.Public |
BindingFlags.Static);
// sort properties by name
Array.Sort(propertyInfos,
delegate (PropertyInfo propertyInfo1,PropertyInfo propertyInfo2) { return propertyInfo1.Name.CompareTo(propertyInfo2.Name); });
// write property names
foreach (PropertyInfo propertyInfo in propertyInfos) {
propList.Add(propertyInfo.Name);
}
return propList;
}
I need to get the List of property name
Expected output: GetProperty<Foo>()
new List<string>() {
"PropA",
"PropB"
}
I tried lot of stackoverlow reference, but I can't able to get the expected output.
Reference:
c# getting ALL the properties of an object
How to get the list of properties of a class?
Kindly assist me.
Your binding flags are incorrect.
Since your properties are not static properties but rather instance properties, you need to replace BindingFlags.Static with BindingFlags.Instance.
propertyInfos = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
This will appropriately look for public, instance, non-static properties on your type. You can also omit the binding flags entirely and get the same results in this case.
I'm a PHP Developer...
I need to do a class that can be created and fill of dynamic way, similar to this in PHP.
class Person{
private $name;
private $age;
function __construct($params = array()){
foreach ($this as $key => $val) {
$this -> $key = (isset($params[$key])) ? $params[$key] : "";
}
}
function getName(){
return $this->name;
}
function getAge(){
return $this->age;
}
function setName($value){
$this->name = $value;
}
function setAge($value){
$this->age = $value;
}
}
I read about the reflection in C#, but I don't find the correct way to do.
This is my C# code
public class Person
{
private String _name { get { return _name; } set { _name = value; } }
private int _age { get { return _age; } set { _age = value; } }
public Person()
{
}
public Person(Hashtable _data)
{
PropertyInfo[] propertyInfos;
propertyInfos = typeof(Person).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var propInfo in propertyInfos)
{
typeof(Person).GetProperty(propInfo.Name).SetValue(this, _data[propInfo.Name]);
}
}
}
In runtime I get an Exception
Object reference not set to an instance of an object.
The typeof(Person) I try to change it to this.getType() and I get the same.
I hope that can help me.
You are grabbing all properties on the object and then looking them up in the hashtable. You likely want the reverse--all objects in the hashtable set to properties on the object. Otherwise you'll get an exception when you don't specify every single member.
As Alexei points out, the NullReferenceException is due to the second call to GetProperties only returning public properties when no BindingFlags are supplied. Since there are no public properties, you get an exception.
Because C# is strongly typed, you run into a number of issues you don't have in PHP. These include setting a value with an object of a type that doesn't match or convert to the property type, entries in your data parameter that don't exist as properties, etc. I've done my best to document the gotchas I see below.
Here is what the Person class would look like (I've cleaned up some of the style and used classes to make it feel more like a C# class):
public class Person
{
private string name { get; set; }
private int age { get; set; }
public Person()
{
}
public Person(IDictionary<string,object> data)
{
foreach (var value in data)
{
// The following line will be case sensitive. Do you need to standardize the case of the input dictionary before getting the property?
PropertyInfo property = typeof(Person).GetProperty(value.Key, BindingFlags.Instance | BindingFlags.NonPublic);
if (property != null)
{
property.SetValue(this, value.Value); // You are allowing any old object to be set here, so be prepared for conversion and casting exceptions
}
else
{
// How do you want to handle entries that don't map to properties? Ignore?
}
}
}
}
And here is an example of usage:
static void Main(string[] args)
{
var person = new Person(new Dictionary<string,object>() {{"name" ,"Mike"}, {"age", 32}});
}
You should stay away from using var if you're new to the language, it only complicates things.
The propInfo in your foreach-loop already is a PropertyInfo, so you don't need to find it again:
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
PropertyInfo[] propertyInfos = typeof(Person).GetProperties(flags);
foreach (PropertyInfo propInfo in propertyInfos)
{
propInfo.SetValue(this, _data[propInfo.Name]);
}
The NullReferenceException is probably caused by the following part of your original code:
typeof(Person).GetProperty(propInfo.Name)...
Since no BindingFlags are provided to the GetProperty() this time, it looks for public instance properties, and when no such property is found, it returns null (that, or _data is null to begin with).
As others have pointed out, your properties currently will cause StackOverflowExceptions. Try changing them to:
private String _name { get; set; }
private int _age { get; set; }
I am wondering why you would want to do this. There may be better, more idiomatic C#, designs to achieve the behavior you want. But we can't know that because there is no additional contextual information mentioned in the question.
So I will simply try to answer your question. The version below takes your code, using auto properties, and a simple dictionary lookup for the initialization of its members from the supplied dictionary. Also note that this does not require any reflection, because there is nothing dynamic about the members of this class.
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public Person(IDictionary<string, object> data)
{
// What to do if the map does not contain "Name" or "Age" ?
// Right now: initialize to default value.
Name = TryLookup<string>(data, "Name", null);
Age = TryLookup<int>(data, "Age", default(int));
// What to do if the map contains other items that do not
// map to a member variable?
}
private static T TryLookup<T>(IDictionary<string, object> data, string key, T defaultValue)
{
return data.ContainsKey(key) ? (T)data[key] : defaultValue;
}
}
In case you actually really really badly need a dynamic type as opposed to a statically defined type with fixed member properties, you could use an ExpandoObject or alternatively (but this is far from trivial) build a dynamic type using an AssemblyBuilder with a TypeBuilder
I wrote a function that copies the properties of one class to another so make a copy of an object.
So something like
MyObject myObject = myOtherObject.MyCustomCopy(myObject)
where myObject and myOtherObject are of the same type. I do it by bascually doing
myObject.prop1 = myOtherObject.prop1
myObject.prop2 = myOtherObject.prop2
myObject.prop3 = myOtherObject.prop3
return myObject
I am pretty sure in the past I used a .NET object that automaticaly did this, by reflection I guess, but can't remember it ... or an I imagining that such a method exists?
Yes I'm aware of auto mapper but i was sure (not so much now) that there is a .NET object that does the job. Maybe not!
You may take a look at AutoMapper.
public static class ext
{
public static void CopyAllTo<T>(this T source, T target)
{
var type = typeof(T);
foreach (var sourceProperty in type.GetProperties())
{
var targetProperty = type.GetProperty(sourceProperty.Name);
targetProperty.SetValue(target, sourceProperty.GetValue(source, null), null);
}
foreach (var sourceField in type.GetFields())
{
var targetField = type.GetField(sourceField.Name);
targetField.SetValue(target, sourceField.GetValue(source));
}
}
}
You should use AutoMapper it was built for this job.
System.Object.MemberwiseClone()
Try description in this link:
.NET Reflection - Copy Class Properties
This code should work for basic property types, not sure how it'll go for anything complex (lists, arrays, custom classes). Should be a starting point though:
public class MyClass
{
public int A { get; set; }
public string B { get; set; }
}
private void button1_Click(object sender, EventArgs e)
{
MyClass orig = new MyClass() { A = 1, B = "hello" };
MyClass copy = new MyClass();
PropertyInfo[] infos = typeof(MyClass).GetProperties();
foreach (PropertyInfo info in infos)
{
info.SetValue(copy, info.GetValue(orig, null), null);
}
Console.WriteLine(copy.A + ", " + copy.B);
}
I know the OP did not ask for a Type to another Type but my variant is one I use for DI in startup.cs for mismatches in configurations between cloud and local dev environment. My local class generally uses a Interface class behind the scenes to map the configurations. Then I use this method to copy properties where they match in name only. I am not checking property types since these are configurations. AutoMapper was suggested. I don't use AutoMapper because we are restricted by U.S. DOD to certain providers. Getting an ATO is hard enough just using .NET, we don't need any more grief.
using System.Linq;
public static class PropertyCopy
{
public static void CopyAllTo<T,T1>(this T source, T1 target)
{
var type = typeof(T);
var type1 = typeof(T1);
foreach (var sourceProperty in type.GetProperties())
{
foreach (var targetProperty in type1.GetProperties()
.Where(targetProperty => sourceProperty.Name == targetProperty.Name)
.Where(targetProperty => targetProperty.SetMethod != null))
{
targetProperty.SetValue(target, sourceProperty.GetValue(source, null), null);
}
}
foreach (var sourceField in type.GetFields())
{
foreach (var targetField in type1.GetFields()
.Where(targetField => sourceField.Name == targetField.Name))
{
targetField.SetValue(target, sourceField.GetValue(source));
}
}
}
}
In very simple terms: As we know Classes are reference types in C#.NET i.e. when we create a object of a class such as
Customer C1=new Customer();
C1.Id=1;
C1.Name="Rakesh";
Then C1(Reference variable) is stored on memory stack and object new Customer() is stored on Heap.
Hence when we copy a class into another class which is basically your question you can do something like below:
Customer C2=C1;
Doing above will copy the C1 Reference variable into C2 But why I wrote about Stack and Heap because using C2 reference variable you can change the object properties being both C1 and C2 pointing to same object in HEAP.Something Like
C2.Id=1;
C2.Name="Mukesh";
Now if you will try to access C1.Name you will see it is changed to "Mukesh".
you can use JsonConvert like this:
string jsonString = JsonConvert.SerializeObject(MyObject);
MyClass object = JsonConvert.DeserializeObject<MyClass>(jsonString);
So what I have right now is something like this:
PropertyInfo[] info = obj.GetType().GetProperties(BindingFlags.Public);
where obj is some object.
The problem is some of the properties I want aren't in obj.GetType() they're in one of the base classes further up. If I stop the debugger and look at obj, the I have to dig through a few "base" entries to see the properties I want to get at. Is there some binding flag I can set to have it return those or do I have to recursively dig through the Type.BaseType hierarchy and do GetProperties on all of them?
Use this:
PropertyInfo[] info = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
EDIT: Of course the correct answer is that of Jay. GetProperties() without parameters is equivalent to GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static ). The BindingFlags.FlattenHierarchy plays no role here.
I don't think it's that complicated.
If you remove the BindingFlags parameter to GetProperties, I think you get the results you're looking for:
class B
{
public int MyProperty { get; set; }
}
class C : B
{
public string MyProperty2 { get; set; }
}
static void Main(string[] args)
{
PropertyInfo[] info = new C().GetType().GetProperties();
foreach (var pi in info)
{
Console.WriteLine(pi.Name);
}
}
produces
MyProperty2
MyProperty
If you access Type.BaseType, you can get the base type. You can recursively access each base type and you'll know when you've hit the bottom when your type is System.Object.
Type type = obj.GetType();
PropertyInfo[] info = type.GetProperties(BindingFlags.Public);
PropertyInfo[] baseProps = type.BaseType.GetProperties(BindingFlags.Public);
I would tend to agree with Nicolas; unless you know you need reflection, then ComponentModel is a viable alternative, with the advantage that you will get the correct metadata even for runtime models (such as DataView/DataRowView).
For example:
foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(obj))
{
Console.WriteLine("{0}={1}", prop.Name, prop.GetValue(obj));
}
As an aside, you can also do some simple performance tricks with this; you can do the same with reflection and Delegate.CreateDelegate, but there is no centralised place to hide the logic away, unlike TypeDescriptor with a TypeDescriptionProvider (don't worry if these are unfamiliar; you can just use the code "as is" ;-p).
Use:
TypeDescriptor.GetProperties(obj);
Just to be complete, you can't get PRIVATE fields and properties from base classes this way. You'll have to use a recursive loop for that:
public static IEnumerable<PropertyInfo> GetProperties(Type type, bool forGetter)
{
// Loop over public and protected members
foreach (var item in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
yield return item;
}
// Get first base type
type = type.BaseType;
// Find their "private" memebers
while (type != null && type != typeof(object))
{
// Loop over non-public members
foreach (var item in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic))
{
// Make sure it's private!
// To prevent doubleing up on protected members
var methodInfo = forGetter ? item.GetGetMethod(true) : item.GetSetMethod(true);
if (methodInfo != null && methodInfo.IsPrivate)
{
yield return item;
}
}
// Get next base type.
type = type.BaseType;
}
}
and
public static IEnumerable<FieldInfo> GetFields(Type type)
{
// Loop over public and protected members
foreach (var item in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
yield return item;
}
// Get first base type
type = type.BaseType;
// Find their "private" memebers
while (type != null && type != typeof(object))
{
// Loop over non-public members
foreach (var item in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
{
// Make sure it's private!
// To prevent doubleing up on protected members
if (item.IsPrivate)
{
yield return item;
}
}
// Get next base type.
type = type.BaseType;
}
}
Note: you will get PROTECTED fields & properties twice.