Get value from nested class using reflection - c#

public class CustomProperty<T>
{
private T _value;
public CustomProperty(T val)
{
_value = val;
}
public T Value
{
get { return this._value; }
set { this._value = value; }
}
}
public class CustomPropertyAccess
{
public CustomProperty<string> Name = new CustomProperty<string>("cfgf");
public CustomProperty<int> Age = new CustomProperty<int>(0);
public CustomPropertyAccess() { }
}
//I jest beginer in reflection.
//How can access GetValue of CPA.Age.Value using fuly reflection
private void button1_Click(object sender, EventArgs e)
{
CustomPropertyAccess CPA = new CustomPropertyAccess();
CPA.Name.Value = "lino";
CPA.Age.Value = 25;
//I did like this . this is the error “ Non-static method requires a target.”
MessageBox.Show(CPA.GetType().GetField("Name").FieldType.GetProperty("Value").GetValue(null ,null).ToString());
}

How about a method like this:
public Object GetPropValue(String name, Object obj) {
foreach (String part in name.Split('.')) {
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
And use it like so:
Object val = GetPropValue("Age.Value", CPA);

Read the error message.
Non-static methods and properties are associated with an instance of a class - and so you need to provide an instance when trying to access them through reflection.

In the GetProperty.GetValue method, you need to specify the object for which you want to get the property value. In your case, it would be: GetValue(CPA ,null)

Related

How to call constructor method with generic type not known at compile time

Platform: .NET framework 4.5.1, C#
I am attempting to call the constructor for a class, not knowing the generic type at run-time and wondering how I could do this. Based on other answers I have read, it’s clear that I need to rely on Reflection.
I have tried a method that includes me getting the MethodInfo array of the constructors and use that, however I am still struggling to put everything together. Below my classes.
I have a parent abstract class, defined like below.
public abstract class ParentClass {
public string name {get;}
public CustomEnum type {get;}
public object value {get;}
public ParentClass(string name, CustomEnum type, object value = null){
this.name = name;
this.type = type;
this.value = value;
}
}
One of the many implementations of the abstract class depends on a GenericType, defined like below.
public class ChildClass<GenericType> : ParentClass {
public delegate GenericType FunctionPointer(ExternalObject object);
public override string name {get;}
public override CustomEnum type {get;}
public FunctionPointer mappingFunction = null;
private ExternalObject _value {get;}
private List<GenericType> mappedValues = null;
private override object value {get => getValue(); set => setValue(value); }
public ChildClass(string name, CustomEnum type, ExternalObject value = null, FunctionPointer mappingFunction = null){
this.name = name;
this.type = type;
this._value = value;
this.mappingFunction = mappingFunction;
populateList(value);
}
private void populateList(ExternalObject value){
if(this.mappingFunction != null){
if(value != null){
this.mappedValues = new List<GenericType>();
foreach(var item in value){
GenericType valueToAdd = mappingFunction.Invoke(value);
this.mappedValues.Add(valueToAdd);
}
}
}
}
private object getValue(){
if(this.mappingFunction == null){
return this._value;
}
else {
return this.mappedValues;
}
}
private void setValue(object value){
this._value = value;
if(this.mappingFunction != null){
populateList(this._value);
}
}
}
This is how I have the process code set up:
public ParentClass[] getValues(ParentClass[] inputParameters){
ParentClass[] outputParameters = null;
if(inputParameters != null){
List<ParentClass> outputList = new List<ParentClass>();
foreach(ParentClass inputParameter in inputParameters){
object value = obtainValue(inputParameter);
ParentClass populatedParameter = populateParameter(inputParameter, value);
outputList.Add(populatedParameter);
}
outputParameters = outputList.ToArray<ParentClass>();
}
return outputParameters;
}
The method I am specifically trying to code for, is as follows:
private ParentClass populateParameter(ParentClass inputParameter, object value){
ParentClass populatedParameter = null;
if(inputParameter != null){
switch(inputParameter.type){
case CustomEnum.WITHOUT_GENERIC_TYPE:
[...]
break;
case CustomEnum.WITH_GENERIC_TYPE:
populatedParameter = populateGenericParameter(inputParameter, (ExternalObject) value);
break;
}
}
return populatedParameter;
}
I am stuck trying to understand how to craft the below method:
private ParentClass populateGenericParameter(ParentClass inputParameter, ExternalObject value) {
ParentClass populatedParameter = null;
FieldInfo functionPointer = null;
Type genericType = typeof(ChildClass<>).MakeGenericType(new object[] { inputParameter.getType() });
FieldInfo[] parameterFields = genericType.GetFields();
if(parameterFields != null){
const string functionPointerString = "FunctionPointer";
foreach(FieldInfo parameterField in parameterFields){
if(parameterField.ToString().ToUpper().Contains(functionPointerString.ToUpper()) == true){
functionPointer = parameterField;
}
}
}
ConstructorInfo[] allConstructors = genericType.GetConstructors();
if(allConstructors != null && allConstructor.Length > 0){
ConstructorInfo constructor = allConstructor[0];
object[] constructorParameters = new object[] {parameter.name, parameter.type, value, functionPointer.GetValue(null) };
populatedParameter = (ChildClass<>) constructor.Invoke(constructorParameters);
}
return populatedParameter;
}
So, the problem is with the constructorParameters object and the Invoke method.
The "functionPointer.GetValue(null)" throws an exception saying that "non-static field requires a target".
The casting of ChildClass when invoking the constructor is a compile-time error, and so far the only way to get around it has been to replace it with the ParentClass.
I am new to reflection, so looking forward to read how to get around this problem. I have visited other topics as well, and that has led me to try to use the ConstructorInfo and FieldInfo arrays. I seem stuck here though. I hope what I am trying to achieve is possible.
Ok, so I figured out the answer. Leaving it here for people that may need it in the future.
First we create the method that will use reflection:
private ParentClass populateGenericParameter(ParentClass inputParameter, ExternalObject value) {
const string methodToInvoke = "initializeParameter";
ParentClass populatedParameter = null;
try {
MethodInfo method = typeof(this).GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
Type type = typeof(ChildClass<>).MakeGenericType(new Type[] {inputParameter.GetType()}).GetGenericArguments()[0].GetGenericArguments()[0];
if(type != null) {
MethodInfo genericMethod = method.MakeGenericMethod(type);
object[] methodArguments = new object[] {inputParameter, value};
populatedParameter = (ParentClass) genericMethod.Invoke(obj: this, parameters: methodArguments);
}
}
catch(Exception e) {
//logging here
}
return populatedParameter;
}
Then, we create the method that will be triggered by reflection:
private ChildClass<GenericType> initializeParameter<GenericType>(ChildClass<GenericType> inputParameter, ExternalObject value){
ChildClass<GenericType> populatedParameter = null;
if(inputParameter != null){
populatedParameter = new ChildClass<GenericType>(parameter.name, parameter.type, value, parameter.mappingFunction);
}
return populatedParameter
}

ExpandoObject add Property with "extra"-code

I've read some stuff about the ExpandoObject, and that I can expand it with properties,fields,methods.
//that's how to add a property to an ExpandoObject.
dynamic x = new ExpandoObject();
x.NewProp = string.Empty;
But sometimes, it could be handy to add a property with some "extra-code".
class sample
{
// a sample field.
public string sampleString{get;set}
// a sample property with some "extra code"
private string s;
public string sampleExtraString
{
get{return s;}
set{s=value;Console.WriteLine(s);}
}
}
Now my question is, how can I add a property to the ExpandoObject that will execute my Console.WriteLine(s); for example on set.
ExpandoObject implements INotifyPropertyChanged, as explained here
(at the bottom of the page)
((INotifyPropertyChanged)x).PropertyChanged +=
new PropertyChangedEventHandler(Expando_PropertyChanged);
x.NewProp = string.Empty;
private static void Expando_PropertyChanged(object sender,
PropertyChangedEventArgs e)
{
Console.WriteLine("{0} has changed.", e.PropertyName);
}
I think a better approach would be using DynamicObject which you can intercept the calls for methods and properties.
This is a simple example, a more robust one would not use reflection to perform set/get operations on the property but rather using reflection.Emit or any compiled operation strategy.
public class Sample
{
public string SampleExtraString { get; set; }
}
public class Factory
{
public class ExtraPropertyObject<T> : DynamicObject
{
private readonly T instance = default(T);
private readonly Type instanceType = null;
public ExtraPropertyObject(T instance) {
this.instance = instance;
instanceType = instance.GetType();
}
public override bool TrySetMember(SetMemberBinder binder, object value) {
PropertyInfo prop = null;
if (binder.Name.Equals("SampleExtraString")) {
Console.WriteLine(value);
}
prop = instanceType.GetProperty(binder.Name);
if (prop != null) {
try {
prop.SetValue(instance, value);
return true;
}
catch (Exception ex) {
}
}
return false;
}
public override bool TryGetMember(GetMemberBinder binder, out object result) {
var prop = instanceType.GetProperty(binder.Name);
if (prop != null) {
try {
result = prop.GetValue(instance);
return true;
}
catch (Exception ex) {
}
}
result = null;
return false;
}
}
public static dynamic CreateInstance<TInstance>() where TInstance : class, new() {
return new ExtraPropertyObject<TInstance>(new TInstance());
}
public static dynamic CreateInstance<TInstance>(TInstance instance) {
return new ExtraPropertyObject<TInstance>(instance);
}
}
class Program
{
static void Main(string[] args) {
var instance = Factory.CreateInstance<Sample>();
instance.SampleExtraString = "value";
Console.WriteLine("Get Operation: {0}", instance.SampleExtraString);
}
}

Get name of a property and declaring class

How can I use reflection to get the name and declaring class of a property of a generic type. The purpose is to get an exception if I read a property where nothing has been written so far. One of the problems is that the check must be independent of the declaring class.
value.GetType().DeclaringType is always null.
using System;
namespace TestCodeContract
{
public struct CheckForNull<T> where T : struct
{
private T? backingField;
public static implicit operator T(CheckForNull<T> value)
{
if (!(value.backingField.HasValue))
{
var t1 = value.GetType().DeclaringType; // always null.
var propertyName = "Delta"; // TODO get from Reflection
var className = "ContractClass"; // TODO get from Reflection
var msg = String.Format("Proprety '{0}' in class '{1}' is not initialized", propertyName, className);
throw new ApplicationException(msg);
}
return value.backingField.Value;
}
public static implicit operator CheckForNull<T>(T value)
{
return new CheckForNull<T> { backingField = value };
}
}
public class ContractClass
{
public CheckForNull<int> Delta { get; set; }
public void Test1()
{
int x = Delta; // Wanted: "Property 'Delta' in class 'ContractClass' is not initialized"
}
}
}
No, you can't do it like that. I would suggest something like this instead:
// You could do this without the constraint, with a bit of extra work.
public class ReadOnlyAfterWrite<T> where T : struct
{
private T? value;
private readonly string property;
private readonly string type;
public ReadOnlyAfterWrite(string property, string type)
{
this.property = property;
this.type = type;
}
public T Value
{
get
{
if (value == null)
{
// Use type and property here
throw new InvalidOperationException(...);
}
return (T) value;
}
set { this.value = value; }
}
}
public class ContractClass
{
// This is what I'd do in C# 6. Before that, probably just use string literals.
private readonly ReadOnlyAfterWrite<int> delta =
new ReadOnlyAfterWrite(nameof(Delta), nameof(ContractClass));
public int Delta
{
get { return delta.Value; }
set { delta.Value = value; }
}
}
While it's not terribly clean in implementation, I think it's a better public API - the fact that it's guarded is invisible to the caller, who just sees an int property.

SetValue within reflected ProperyInfo

I am using reflection to set a property from within a reflected property. I have to use reflection as I don't know what the type the child propery will be, but each time I get System.Target.TargetException (on the prop.SetValue) prop is pointing to the correct property
I can find lot of examples of the SetValue, the problem that I am having, is I expect related to the fact that selectSubProcess is a PropertyInfo rather than a actual class
PropertyInfo selectedSubProcess = process.GetProperty(e.ChangedItem.Parent.Label);
Type subType = selectedSubProcess.PropertyType;
PropertyInfo prop = subType.GetProperty(e.ChangedItem.Label + "Specified");
if (prop != null)
{
prop.SetValue(process, true, null);
}
It looks like process is "Type", not an instance of an object. in the line
prop.SetValue(process, true, null);
you need an instance of an object to set, not a Type.
Use "GetValue" to get an instance of the object you care about:
public void test()
{
A originalProcess = new A();
originalProcess.subProcess.someBoolean = false;
Type originalProcessType = originalProcess.GetType();
PropertyInfo selectedSubProcess = originalProcessType.GetProperty("subProcess");
object subProcess = selectedSubProcess.GetValue(originalProcess, null);
Type subType = selectedSubProcess.PropertyType;
PropertyInfo prop = subType.GetProperty("someBoolean");
if (prop != null)
{
prop.SetValue(subProcess, true, null);
}
MessageBox.Show(originalProcess.subProcess.someBoolean.ToString());
}
public class A
{
private B pSubProcess = new B();
public B subProcess
{
get
{
return pSubProcess;
}
set
{
pSubProcess = value;
}
}
}
public class B
{
private bool pSomeBoolean = false;
public bool someBoolean
{
get
{
return pSomeBoolean;
}
set
{
pSomeBoolean = true;
}
}
}

Reading attribute of a property using reflection

I need to read the attribute of a property using reflection
For example I get the following :
[XmlElement("Id")]
[CategoryAttribute("Main"), ReadOnly(true),
Description("This property is auto-generated")]
[RulesCriteria("ID")]
public override string Id
{
get { return _ID; }
set
{
_ID = value;
}
}
i want to get the " read only "value of this property using reflection
can anybody help
It's difficult to write the code for your case without knowing the Type name. Hope below example helps.
using System;
using System.Reflection;
public class Myproperty
{
private string caption = "Default caption";
public string Caption
{
get{return caption;}
set {if(caption!=value) {caption = value;}
}
}
}
class Mypropertyinfo
{
public static int Main(string[] args)
{
Console.WriteLine("\nReflection.PropertyInfo");
// Define a property.
Myproperty Myproperty = new Myproperty();
Console.Write("\nMyproperty.Caption = " + Myproperty.Caption);
// Get the type and PropertyInfo.
Type MyType = Type.GetType("Myproperty");
PropertyInfo Mypropertyinfo = MyType.GetProperty("Caption");
// Get and display the attributes property.
PropertyAttributes Myattributes = Mypropertyinfo.Attributes;
Console.Write("\nPropertyAttributes - " + Myattributes.ToString());
return 0;
}
}
MSDN
public static bool PropertyReadOnlyAttributeValue(PropertyInfo property)
{
ReadonlyAttribute attrib = Attribute.GetCustomAttribute(property, typeof(ReadOnlyAttribute));
return attrib != null && attrib.IsReadOnly;
}
public static bool PropertyReadOnlyAttributeValue(Type type, string propertyName)
{
return PropertyReadOnlyAttributeValue(type.GetProperty(propertyName));
}
public static bool PropertyReadOnlyAttributeValue(object instance, string propertyName)
{
if (instance != null)
{
Type type = instance.GetType();
return PropertyReadOnlyAttributeValue(type, propertyName);
}
return false;
}

Categories