How to pick up attribute dynamically

Asked

Viewed 694 times

6

How I would make 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 dynamism is in the variable $a, in which if I change to x me returns the value of teste->x.

That’s possible?

  • 1

    http://stackoverflow.com/questions/1196991/get-property-value-from-string-using-reflection-in-c-sharp and https://msdn.microsoft.com/en-us/library/kz0a8sxy(v=vs.110). aspx

  • @bfavaretto worked, I just had to take care of the cast that was generating error :D

1 answer

2


It is possible to get this through reflection. C# is a static language, so there is no reason why it should have facilities ready for direct access. But it is possible to create a class with some extension methods to facilitate 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;
    }
}

Behold working in the ideone. And in the .NET Fiddle. Also put on the Github for future reference.

I modified the code to make it more idiomatic on Teste and more similar to the example used in PHP on 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 know why you are doing it). Sure, you can create it however you want, but the basis is this.

Remember that if you want to have the same semantics as the PHP classes, you need to use another type of structure. In PHP the class is actually a data dictionary, not a static structure. In C# you can create a class based on a data dictionary and keep a cleaner syntax through the ExpandoObject. In this way the reflection is embedded in the class itself. You can access with class syntax, or with 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"]);

As you can see what you want is to take the fields and not attributes that do not exist in the code, use the correct terms.

  • using static it’s like grape passes on Christmas dinner, there’s always someone who likes, rs.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.