Obter o valor da propriedade do texto usando a reflexão em C#

Estou a tentar implementar a transformação de dados usando a reflexão.1 exemplo no meu código.

a função GetSourceValue tem um interruptor comparando vários tipos, mas eu quero remover estes tipos e propriedades e ter GetSourceValue Obter o valor da propriedade usando apenas uma única cadeia de caracteres como parâmetro. Eu quero passar uma classe e propriedade na cadeia e resolver o valor da propriedade.

Isto é possível?

1versão do pacote Web de publicação original no blog

 700
Author: GlenH7, 2009-07-29

21 answers

 public static object GetPropValue(object src, string propName)
 {
     return src.GetType().GetProperty(propName).GetValue(src, null);
 }
É claro que vai querer adicionar validação e outras coisas, mas esse é o essencial.
 1399
Author: Ed S., 2013-05-03 23:12:20
Que tal algo assim?
public static Object GetPropValue(this Object obj, String name) {
    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;
}

public static T GetPropValue<T>(this Object obj, String name) {
    Object retval = GetPropValue(obj, name);
    if (retval == null) { return default(T); }

    // throws InvalidCastException if types are incompatible
    return (T) retval;
}

Isto permitir-lhe-á descer às propriedades usando uma única cadeia de caracteres, do seguinte modo:

DateTime now = DateTime.Now;
int min = GetPropValue<int>(now, "TimeOfDay.Minutes");
int hrs = now.GetPropValue<int>("TimeOfDay.Hours");

Pode utilizar estes métodos como métodos estáticos ou extensões.

 176
Author: jheddings, 2012-11-08 15:23:00

Adicionar a qualquer Class:

public class Foo
{
    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
    }

    public string Bar { get; set; }
}

Então, pode usar como:

Foo f = new Foo();
// Set
f["Bar"] = "asdf";
// Get
string s = (string)f["Bar"];
 47
Author: Eduardo Cuomo, 2014-07-23 19:58:10

Que tal usar o CallByName do espaço de nomes Microsoft.VisualBasic? Ele usa reflexão para obter propriedades, campos e métodos de objetos normais, objetos COM e até mesmo objetos dinâmicos.

using Microsoft.VisualBasic;
using Microsoft.VisualBasic.CompilerServices;

E depois

Versioned.CallByName(this, "method/function/prop name", CallType.Get).ToString();
 39
Author: Fredou, 2014-11-02 18:04:26
Grande resposta de jheddings. Eu gostaria de melhorá-lo, permitindo referenciação de conjuntos agregados ou coleções de objetos, para que o nome próprio possa ser apropriado1.property2 [X].propriedade 3:
    public static object GetPropertyValue(object srcobj, string propertyName)
    {
        if (srcobj == null)
            return null;

        object obj = srcobj;

        // Split property name to parts (propertyName could be hierarchical, like obj.subobj.subobj.property
        string[] propertyNameParts = propertyName.Split('.');

        foreach (string propertyNamePart in propertyNameParts)
        {
            if (obj == null)    return null;

            // propertyNamePart could contain reference to specific 
            // element (by index) inside a collection
            if (!propertyNamePart.Contains("["))
            {
                PropertyInfo pi = obj.GetType().GetProperty(propertyNamePart);
                if (pi == null) return null;
                obj = pi.GetValue(obj, null);
            }
            else
            {   // propertyNamePart is areference to specific element 
                // (by index) inside a collection
                // like AggregatedCollection[123]
                //   get collection name and element index
                int indexStart = propertyNamePart.IndexOf("[")+1;
                string collectionPropertyName = propertyNamePart.Substring(0, indexStart-1);
                int collectionElementIndex = Int32.Parse(propertyNamePart.Substring(indexStart, propertyNamePart.Length-indexStart-1));
                //   get collection object
                PropertyInfo pi = obj.GetType().GetProperty(collectionPropertyName);
                if (pi == null) return null;
                object unknownCollection = pi.GetValue(obj, null);
                //   try to process the collection as array
                if (unknownCollection.GetType().IsArray)
                {
                    object[] collectionAsArray = unknownCollection as Array[];
                    obj = collectionAsArray[collectionElementIndex];
                }
                else
                {
                    //   try to process the collection as IList
                    System.Collections.IList collectionAsList = unknownCollection as System.Collections.IList;
                    if (collectionAsList != null)
                    {
                        obj = collectionAsList[collectionElementIndex];
                    }
                    else
                    {
                        // ??? Unsupported collection type
                    }
                }
            }
        }

        return obj;
    }
 23
Author: AlexD, 2014-09-02 21:53:53

Se eu usar o código de ed S. eu consigo

'ReflectionExtensions.GetProperty (Type, string)' is inacessible due to its protection level

Parece que GetProperty() não está disponível em Xamarin.Formulario. TargetFrameworkProfile está Profile7 Na Minha Biblioteca de classe portátil (. NET Framework 4.5, Windows 8, ASP.NET Core 1.0, Xamarin.Andróide, Xamarin.iOS, Xamarin.iOS Classic).

Agora encontrei uma solução de trabalho.
using System.Linq;
using System.Reflection;

public static object GetPropValue(object source, string propertyName)
{
    var property = source.GetType().GetRuntimeProperties().FirstOrDefault(p => string.Equals(p.Name, propertyName, StringComparison.OrdinalIgnoreCase));
    return property?.GetValue(source);
}

Origem

 7
Author: testing, 2018-10-04 10:18:44

Sobre a discussão sobre propriedades aninhadas, você pode evitar todas as coisas de reflexão se você usar o DataBinder.Eval Method (Object, String) como se segue:

var value = DataBinder.Eval(DateTime.Now, "TimeOfDay.Hours");
É claro que vai precisar de adicionar uma referência à Assembleia, mas isto não deve ser nada de especial.
 6
Author: Rubens Farias, 2015-07-29 14:19:48

Usando o Proprietyinfo do sistema .Reflexão espaço de nomes. A reflexão compila muito bem, independentemente da propriedade a que tentemos aceder. O erro surgirá durante o período de execução.

    public static object GetObjProperty(object obj, string property)
    {
        Type t = obj.GetType();
        PropertyInfo p = t.GetProperty("Location");
        Point location = (Point)p.GetValue(obj, null);
        return location;
    }

Funciona bem para obter a propriedade de localização de um objecto

Label1.Text = GetObjProperty(button1, "Location").ToString();
Vamos ter a localização: {X = 71, Y = 27} Também podemos devolver a localização.X ou localização.E na mesma direcção.
 4
Author: A Ghazal, 2015-10-23 14:47:22

O método de chamada foi alterado na norma. NET (a partir de 1.6). Também podemos usar o operador condicional nulo C# 6.

using System.Reflection; 
public static object GetPropValue(object src, string propName)
{
    return src.GetType().GetRuntimeProperty(propName)?.GetValue(src);
}
 4
Author: Matt Frear, 2017-05-25 09:13:23
public static List<KeyValuePair<string, string>> GetProperties(object item) //where T : class
    {
        var result = new List<KeyValuePair<string, string>>();
        if (item != null)
        {
            var type = item.GetType();
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var pi in properties)
            {
                var selfValue = type.GetProperty(pi.Name).GetValue(item, null);
                if (selfValue != null)
                {
                    result.Add(new KeyValuePair<string, string>(pi.Name, selfValue.ToString()));
                }
                else
                {
                    result.Add(new KeyValuePair<string, string>(pi.Name, null));
                }
            }
        }
        return result;
    }

Esta é uma forma de obter todas as propriedades com os seus valores numa lista.

 3
Author: Бончо Вълков, 2016-01-06 13:46:24

Aqui está outra maneira de encontrar uma propriedade aninhada que não requer a string para lhe dizer o caminho de nidificação. Crédito à Ed S. para o método da propriedade única.

    public static T FindNestedPropertyValue<T, N>(N model, string propName) {
        T retVal = default(T);
        bool found = false;

        PropertyInfo[] properties = typeof(N).GetProperties();

        foreach (PropertyInfo property in properties) {
            var currentProperty = property.GetValue(model, null);

            if (!found) {
                try {
                    retVal = GetPropValue<T>(currentProperty, propName);
                    found = true;
                } catch { }
            }
        }

        if (!found) {
            throw new Exception("Unable to find property: " + propName);
        }

        return retVal;
    }

        public static T GetPropValue<T>(object srcObject, string propName) {
        return (T)srcObject.GetType().GetProperty(propName).GetValue(srcObject, null);
    }
 2
Author: Recursor, 2014-11-05 00:38:13

Nunca mencionas o objecto que estás a inspeccionar, e como estás a rejeitar aqueles que referem um dado objecto, vou assumir que queres dizer um objecto estático.

using System.Reflection;
public object GetPropValue(string prop)
{
    int splitPoint = prop.LastIndexOf('.');
    Type type = Assembly.GetEntryAssembly().GetType(prop.Substring(0, splitPoint));
    object obj = null;
    return type.GetProperty(prop.Substring(splitPoint + 1)).GetValue(obj, null);
}

Note que marquei o objecto que está a ser inspeccionado com a variável local obj. null significa estática, caso contrário configure-a como quiser. Note também que o GetEntryAssembly() é um dos poucos métodos disponíveis para obter a montagem "running", você pode querer brincar com ele se você está tendo dificuldade em carregar o tipo.

 2
Author: Guvante, 2015-08-06 08:56:27

O seguinte código é um método recursivo para mostrar toda a hierarquia de todos os nomes de Propriedades e valores contidos na instância de um objeto. Este método usa uma versão simplificada da resposta de AlexD GetPropertyValue() acima neste tópico. Graças a este tópico de discussão, eu fui capaz de descobrir como fazer isso!

Por exemplo, uso este método para mostrar uma explosão ou descarga de todas as propriedades numa resposta {[[2]} chamando o método da seguinte forma:

PropertyValues_byRecursion("Response", response, false);

public static object GetPropertyValue(object srcObj, string propertyName)
{
  if (srcObj == null) 
  {
    return null; 
  }
  PropertyInfo pi = srcObj.GetType().GetProperty(propertyName.Replace("[]", ""));
  if (pi == null)
  {
    return null;
  }
  return pi.GetValue(srcObj);
}

public static void PropertyValues_byRecursion(string parentPath, object parentObj, bool showNullValues)
{
  /// Processes all of the objects contained in the parent object.
  ///   If an object has a Property Value, then the value is written to the Console
  ///   Else if the object is a container, then this method is called recursively
  ///       using the current path and current object as parameters

  // Note:  If you do not want to see null values, set showNullValues = false

  foreach (PropertyInfo pi in parentObj.GetType().GetTypeInfo().GetProperties())
  {
    // Build the current object property's namespace path.  
    // Recursion extends this to be the property's full namespace path.
    string currentPath = parentPath + "." + pi.Name;

    // Get the selected property's value as an object
    object myPropertyValue = GetPropertyValue(parentObj, pi.Name);
    if (myPropertyValue == null)
    {
      // Instance of Property does not exist
      if (showNullValues)
      {
        Console.WriteLine(currentPath + " = null");
        // Note: If you are replacing these Console.Write... methods callback methods,
        //       consider passing DBNull.Value instead of null in any method object parameters.
      }
    }
    else if (myPropertyValue.GetType().IsArray)
    {
      // myPropertyValue is an object instance of an Array of business objects.
      // Initialize an array index variable so we can show NamespacePath[idx] in the results.
      int idx = 0;
      foreach (object business in (Array)myPropertyValue)
      {
        if (business == null)
        {
          // Instance of Property does not exist
          // Not sure if this is possible in this context.
          if (showNullValues)
          {
            Console.WriteLine(currentPath  + "[" + idx.ToString() + "]" + " = null");
          }
        }
        else if (business.GetType().IsArray)
        {
          // myPropertyValue[idx] is another Array!
          // Let recursion process it.
          PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
        }
        else if (business.GetType().IsSealed)
        {
          // Display the Full Property Path and its Value
          Console.WriteLine(currentPath + "[" + idx.ToString() + "] = " + business.ToString());
        }
        else
        {
          // Unsealed Type Properties can contain child objects.
          // Recurse into my property value object to process its properties and child objects.
          PropertyValues_byRecursion(currentPath + "[" + idx.ToString() + "]", business, showNullValues);
        }
        idx++;
      }
    }
    else if (myPropertyValue.GetType().IsSealed)
    {
      // myPropertyValue is a simple value
      Console.WriteLine(currentPath + " = " + myPropertyValue.ToString());
    }
    else
    {
      // Unsealed Type Properties can contain child objects.
      // Recurse into my property value object to process its properties and child objects.
      PropertyValues_byRecursion(currentPath, myPropertyValue, showNullValues);
    }
  }
}
 2
Author: gridtrak, 2015-08-06 08:56:58
public class YourClass
{
    //Add below line in your class
    public object this[string propertyName] => GetType().GetProperty(propertyName)?.GetValue(this, null);
    public string SampleProperty { get; set; }
}

//And you can get value of any property like this.
var value = YourClass["SampleProperty"];
 2
Author: Komal Narang, 2018-03-06 15:06:15
Dim NewHandle As YourType = CType(Microsoft.VisualBasic.CallByName(ObjectThatContainsYourVariable, "YourVariableName", CallType), YourType)
 1
Author: Kyle, 2011-11-30 23:55:28
Mais curto ....
var a = new Test { Id = 1 , Name = "A" , date = DateTime.Now};
var b = new Test { Id = 1 , Name = "AXXX", date = DateTime.Now };

var compare = string.Join("",a.GetType().GetProperties().Select(x => x.GetValue(a)).ToArray())==
              string.Join("",b.GetType().GetProperties().Select(x => x.GetValue(b)).ToArray());
 1
Author: Budiantowang, 2014-07-13 04:34:29

Jheddings eAlexD ambos escreveram excelentes respostas sobre como resolver cadeias de propriedade. Eu gostaria de colocar o meu na mistura, já que eu escrevi uma biblioteca dedicada exatamente para esse propósito.

Mather.CSharp'a classe principal é Resolver. Por padrão, ele pode resolver propriedades, array e entradas de dicionário.

Então, por exemplo, se você tem um objeto como este
var o = new { Property1 = new { Property2 = "value" } };

E se quiseres Property2, podes fazê - lo assim:

IResolver resolver = new Resolver();
var path = "Property1.Property2";
object result = r.Resolve(o, path); 
//=> "value"

Isto é o exemplo mais básico dos caminhos que pode resolver. Se você quiser ver o que mais ele pode, ou como você pode estendê-lo, basta dirigir-se para a sua página Github.

 1
Author: Domysee, 2017-05-23 11:47:26
public static TValue GetFieldValue<TValue>(this object instance, string name)
{
    var type = instance.GetType(); 
    var field = type.GetFields(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.FieldType) && e.Name == name);
    return (TValue)field?.GetValue(instance);
}

public static TValue GetPropertyValue<TValue>(this object instance, string name)
{
    var type = instance.GetType();
    var field = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance).FirstOrDefault(e => typeof(TValue).IsAssignableFrom(e.PropertyType) && e.Name == name);
    return (TValue)field?.GetValue(instance);
}
 1
Author: Rahma Sammaron, 2017-09-29 16:22:41
Eis a minha solução. Ele também funciona com objetos COM e permite acessar itens de coleta / array a partir de objetos COM.
public static object GetPropValue(this object obj, string name)
{
    foreach (string part in name.Split('.'))
    {
        if (obj == null) { return null; }

        Type type = obj.GetType();
        if (type.Name == "__ComObject")
        {
            if (part.Contains('['))
            {
                string partWithoundIndex = part;
                int index = ParseIndexFromPropertyName(ref partWithoundIndex);
                obj = Versioned.CallByName(obj, partWithoundIndex, CallType.Get, index);
            }
            else
            {
                obj = Versioned.CallByName(obj, part, CallType.Get);
            }
        }
        else
        {
            PropertyInfo info = type.GetProperty(part);
            if (info == null) { return null; }
            obj = info.GetValue(obj, null);
        }
    }
    return obj;
}

private static int ParseIndexFromPropertyName(ref string name)
{
    int index = -1;
    int s = name.IndexOf('[') + 1;
    int e = name.IndexOf(']');
    if (e < s)
    {
        throw new ArgumentException();
    }
    string tmp = name.Substring(s, e - s);
    index = Convert.ToInt32(tmp);
    name = name.Substring(0, s - 1);
    return index;
}
 0
Author: user3175253, 2018-02-24 14:24:34

O método abaixo funciona perfeitamente para mim:

class MyClass {
    public string prop1 { set; get; }

    public object this[string propertyName]
    {
        get { return this.GetType().GetProperty(propertyName).GetValue(this, null); }
        set { this.GetType().GetProperty(propertyName).SetValue(this, value, null); }
    }
}

Para obter o valor da propriedade:

MyClass t1 = new MyClass();
...
string value = t1["prop1].ToString();

Para definir o valor da propriedade:

t1["prop1] = value;
 0
Author: Derrick.X, 2018-07-09 05:19:07
Olha para a Heleonix.Biblioteca de reflexão. Você pode obter/definir / invocar Membros por caminhos, ou criar um getter/setter (lambda compilado em um delegado) que é mais rápido do que a reflexão. Por exemplo:
var success = Reflector.Get(DateTime.Now, null, "Date.Year", out int value);

Ou criar um getter uma vez e cache para reutilização (este é o mais alto desempenho, mas pode jogar de NullReferenceException se um intermediário membro é nulo):

var getter = Reflector.CreateGetter<DateTime, int>("Date.Year", typeof(DateTime));
getter(DateTime.Now);

Ou se quiser criar um List<Action<object, object>> de diferentes getters, basta indicar os tipos de base para os delegados compilados (as conversões de tipo serão adicionadas a lambdas compiladas):

var getter = Reflector.CreateGetter<object, object>("Date.Year", typeof(DateTime));
getter(DateTime.Now);
 0
Author: Hennadii Lutsyshyn, 2018-07-13 10:57:55