How to get attribute dynamically

6

How would I do the following PHP code in C #?

class teste{
    public $x = 10;
    public $y = 10;
}

$n = new teste();
$a = "y";

print_r($n->{$a});

Note that the dynamism is in the variable $a , in which if I change to x it returns me the value of teste->x .

Is this possible?

    
asked by anonymous 23.12.2015 / 01:45

1 answer

2

This is possible through reflection. C # is a static language, so you do not have to have it ready for direct access. But you can create a class with some extension methods to make it easier to use:

using System;
using static System.Console;
using System.Reflection;

public class Program {
    public static void Main() {
        var teste = new Teste();
        teste.ListProperties();
        WriteLine(teste.GetPropValue<int>("y"));
        var teste2 = new Teste2();
        teste2.ListFields();
    }
}

public class Teste {
    public int x { get; set; } = 10;
    public int y { get; set; } = 10;
}

public class Teste2 {
    public int x = 10;
    public int y = 10;
}

public static class ObjectExt {
    public static void ListProperties(this object obj) {
        foreach(var prop in obj.GetType().GetProperties()) {
            WriteLine($"{prop.Name} = {prop.GetValue(obj, null)}");
        }
    }
    public static void ListFields(this object obj) {
        foreach(var field in obj.GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
            WriteLine($"{field.Name} = {field.GetValue(obj)}");
        }
    }
    public static T GetPropValue<T>(this object value, string propertyName) {
        if (value == null) { throw new ArgumentNullException("value"); }
        if (String.IsNullOrEmpty(propertyName)) { throw new ArgumentException("propertyName"); }
        PropertyInfo info = value.GetType().GetProperty(propertyName);
        return (T)info.GetValue(value, null);
    }
    public static FieldInfo GetFieldInfo(this Type objType, string fieldName, BindingFlags flags, bool isFirstTypeChecked = true) {
        FieldInfo fieldInfo = objType.GetField(fieldName, flags);
        if (fieldInfo == null && objType.BaseType != null) {
            fieldInfo = objType.BaseType.GetFieldInfo(fieldName, flags, false);
        }
        if (fieldInfo == null && isFirstTypeChecked) {
            throw new MissingFieldException(String.Format("Field {0}.{1} could not be found with the following BindingFlags: {2}", objType.ReflectedType.FullName, fieldName, flags.ToString()));
        }
        return fieldInfo;
    }
}

See running on dotNetFiddle .

I have modified the code to become more idiomatic in Teste and more like the example used in PHP in Teste2 . The ideal in C # is to prefer the form of properties and not with public fields (which can be used in specific cases, if there is reason and you know why you are doing this). Of course, you can create it any way you want, but the basis is this.

Remember that if you want to have the same semantics of PHP classes, you need to use another kind of structure. In PHP the class is actually a data dictionary, it is not a static structure. In C # you can create a class based on a data dictionary and maintain a cleaner syntax through ExpandoObject . In this way the reflection becomes embedded in the class itself. You can access with the class syntax, or with the dictionary syntax, which is what was used in the PHP example.

dynamic obj = new ExpandoObject();
obj.x = 10;
obj.y = 10;
WriteLine(((IDictionary<string, object>)obj)["y"]);
    
23.12.2015 / 02:38