Get Value from Override using Reflection - c#

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

Related

get field by name

I am trying to create a function that can return a field from its object.
Here is what I have so far.
public class Base
{
public string thing = "Thing";
public T GetAttribute<T>(string _name)
{
return (T)typeof(T).GetProperty(_name).GetValue(this, null);
}
}
What I would ideally like is to call:
string thingy = GetAttribute<string>("thing");
but I have a feeling I got the wrong end of the stick when reading up on this because I keep getting null reference exceptions.
First thing - thing is a field, not a property.
Another thing is that you have to change parameter type to get it working:
public class Base {
public string thing = "Thing";
public T GetAttribute<T> ( string _name ) {
return (T)typeof(Base).GetField( _name ).GetValue (this, null);
}
}
BTW - you can get property/field value by referencing an instance:
var instance = new Base();
var value = instance.thing;
thing is a field not a property. You should use GetField method instead of GetProperty.
Another problem is you are looking in typeof(T). You should look for the field in typeof(Base).
The whole function should be changed to
public T GetAttribute<T>(string _name)
{
return (T)GetType().GetField(_name).GetValue(this);
}
If you want to have an extension method to get field value of a type you can use this
public static class Ex
{
public static TFieldType GetFieldValue<TFieldType, TObjectType>(this TObjectType obj, string fieldName)
{
var fieldInfo = obj.GetType().GetField(fieldName,
BindingFlags.Instance | BindingFlags.Static |
BindingFlags.Public | BindingFlags.NonPublic);
return (TFieldType)fieldInfo.GetValue(obj);
}
}
Use it like
var b = new Base();
Console.WriteLine(b.GetFieldValue<string, Base>("thing"));
Using BindingFlags will help you to get field value even if it is private or static field.

Why I can't assign dynamic data in constructor C#?

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

How to instruct which property should be modified from parameter

If need a way of telling a method which property of a object should be set.
Here's an example:
public class Person
{
public int A { get; set; }
public int B { get; set; }
}
public class PersonController
{
public void Create(int x)
{
var p = new Person();
// How to tell if A or B should be set?
p.A = x;
// or
p.B = x;
}
}
Now this is a very simple example but imagine that I don't know what kind of object I need to modify.
How can I then tell which property needs to be set - A or B?
There are multiple ways of doing it. Here is a list, starting with the most desirable approach to the least desirable:
Make two separate methods, CreateA and CreateB
Pass an Action<Person> for post-initialization
Make an enum WhichOneToSet {SetA, SetB}, and pass a value to Create as a second parameter
Make a variable external to Create. Use that variable to determine the item to be set.
Here is an illustration of approach number three:
public void Create(Action<Person> postInit) {
var p = new Person();
postIniti(p);
...
}
The caller can call it like this:
PersonController ctrl = new PersonController();
ctrl.Create(p => p.A = 123);
ctrl.Create(p => p.B = 456);
You can use reflection to do this:
using System.Reflection;
public class PersonController
{
public void Create(int x, string propName)
{
var p = new Person();
obj.GetType().InvokeMember(propName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder, obj, x);
}
}
For more info see post Set object property using reflection

Name of object within another object

I have a class called Prescriptions. It has properties that are other classes. So, for example, a property name of Fills would be from the PDInt class which has other properties about the value that I need.
If I want to set the value of the Fills property in the Prescription class it would be something like
Prescription p = new Prescription();
p.Fills.Value = 33;
So now I want to take the name of the Fills property and stuff it in a the tag property in a winform control.
this.txtFills.Tag = p.Fills.GetType().Name;
However when I do this, I get the base class of the property, not the property name. So instead of getting "Fills", I get "PDInt".
How do I get the instantiated name of the property?
Thank you.
Below is an extension method that I use it when I wanna work like you:
public static class ModelHelper
{
public static string Item<T>(this T obj, Expression<Func<T, object>> expression)
{
if (expression.Body is MemberExpression)
{
return ((MemberExpression)(expression.Body)).Member.Name;
}
if (expression.Body is UnaryExpression)
{
return ((MemberExpression)((UnaryExpression)(expression.Body)).Operand)
.Member.Name;
}
throw new InvalidOperationException();
}
}
use it as :
var name = p.Item(x=>x.Fills);
For detail about how method works see Expression Tree in .Net
Check this blogpost which is helpful : http://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/
Do this you need to make USe of reflection feature of .net framework.
Something like this
Type type = test.GetType();
PropertyInfo[] propInfos = type.GetProperties();
for (int i = 0; i < propInfos.Length; i++)
{
PropertyInfo pi = (PropertyInfo)propInfos.GetValue(i);
string propName = pi.Name;
}
You can get you like as this ? ↓
public class Prescription
{
public PDInt Fills;
}
public class PDInt
{
public int Value;
}
Prescription p = new Prescription();
foreach(var x in p.GetType().GetFields())
{
// var type = x.GetType(); // PDInt or X //Fills
}

How to loop through class properties tree?

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
}

Categories

Resources