value - working with reflection in c#




Obter valor da propriedade da string usando reflexão em c# (14)

Adicione 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, você pode usar como:

Foo f = new Foo();
// Set
f["Bar"] = "asdf";
// Get
string s = (string)f["Bar"];

Eu estou tentando implementar a transformação de dados usando o exemplo de reflexão 1 no meu código.

A função GetSourceValue tem uma opção que compara vários tipos, mas eu quero remover esses tipos e propriedades e ter GetSourceValue obter o valor da propriedade usando apenas uma única seqüência de caracteres como o parâmetro. Eu quero passar uma classe e propriedade na string e resolver o valor da propriedade.

Isso é possível?

1 versão do arquivo Web da postagem do blog original


Aqui está a minha solução. Ele também funciona com objetos COM e permite acessar itens de coleção / matriz 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;
}

Dê uma olhada na biblioteca Heleonix.Reflection . Você pode obter / definir / invocar membros por caminhos, ou criar um getter / setter (lambda compilado em um delegado) que é mais rápido que reflexão. Por exemplo:

var success = Reflector.Get(DateTime.Now, null, "Date.Year", out int value);

Ou crie um getter uma vez e o cache para reutilização (ele terá mais desempenho, mas poderá lançar NullReferenceException se um membro intermediário for nulo):

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

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

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

Grande resposta por jheddings. Eu gostaria de melhorá-lo permitindo a referência de matrizes agregadas ou coleções de objetos, de modo que propertyName poderia ser property1.property2 [X] .property3:

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

O método abaixo funciona perfeito 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;

O método para chamar foi alterado no .NET Standard (a partir de 1.6). Também podemos usar o operador condicional nulo do C # 6.

using System.Reflection; 
public static object GetPropValue(object src, string propName)
{
    return src.GetType().GetRuntimeProperty(propName)?.GetValue(src);
}

Que tal usar o CallByName do namespace Microsoft.VisualBasic.dll ( Microsoft.VisualBasic.dll )? 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();

Se eu usar o código do Ed S. eu recebo

'ReflectionExtensions.GetProperty (Type, string)' está inacessível devido ao seu nível de proteção

Parece que GetProperty() não está disponível no Xamarin.Forms. TargetFrameworkProfile é Profile7 na minha biblioteca de classes portátil (.NET Framework 4.5, Windows 8, ASP.NET Core 1.0, Xamarin.Android, 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);
}

Source


Usando PropertyInfo do namespace System.Reflection . O Reflection compila muito bem, independentemente da propriedade que tentamos acessar. O erro será exibido durante o tempo 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;
    }

Ele funciona bem para obter a propriedade Location de um objeto

Label1.Text = GetObjProperty(button1, "Location").ToString();

Nós vamos obter a localização: {X = 71, Y = 27} Nós também podemos retornar location.X ou location.Y da mesma maneira.


Você nunca menciona o objeto que está inspecionando e, como está rejeitando aqueles que fazem referência a um determinado objeto, suponho que você esteja falando de um objeto 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);
}

Observe que marquei o objeto que está sendo inspecionado com a variável local obj . null significa static, caso contrário, defina-o como desejado. Observe também que o GetEntryAssembly() é um dos poucos métodos disponíveis para obter o assembly "em execução", você pode querer brincar com ele se você está tendo dificuldade em carregar o tipo.


jheddings e AlexD escreveram excelentes respostas sobre como resolver cadeias de propriedades. Eu gostaria de jogar o meu na mistura, já que escrevi uma biblioteca dedicada exatamente para esse propósito.

A classe principal do Pather.CSharp é o Resolver . Por padrão, ele pode resolver propriedades, matrizes e entradas de dicionário.

Então, por exemplo, se você tem um objeto como este

var o = new { Property1 = new { Property2 = "value" } };

e deseja obter Property2 , você pode fazer assim:

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

Este é o exemplo mais básico dos caminhos que ele pode resolver. Se você quiser ver o que mais pode, ou como você pode estendê-lo, vá para a Pather.CSharp .


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"];

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

 public static object GetPropValue(object src, string propName)
 {
     return src.GetType().GetProperty(propName).GetValue(src, null);
 }

Claro, você vai querer adicionar validação e outros enfeites, mas essa é a essência disso.





reflection