How to create a variable where to access its properties via string?

Asked

Viewed 595 times

12

I’d like to access by string the properties of an object: (EXAMPLE 1)

var cor = casa["cor"];
var tamanho = casa["tamanho"];

Instead of accessing like this: (EXAMPLE 2)

var cor = casa.cor;
var tamanho = casa.tamanho;

Creating this way I access by EXAMPLE 2:

var casa = new {
    cor = "verde",
    tamanho = 2000
}

How would I create the home object to be able to access as in EXAMPLE 1?

  • 1

    Usa json then...

  • Explain a little better what you want. Is this? http://answall.com/a/90671/101

  • I rephrased @bigown, see if it’s a little clearer.

  • Do you want to access both ways? Or do you want to access only from the top form?

  • Only the top shape, via string

  • My understanding was that you want to string in the properties of an object, right? In this case I believe you have to use Reflection.

  • I posted an answer using Reflection which allows you to use exactly as in your example. The object has properties with their respective types and can be read and written identifying them by string.

Show 2 more comments

4 answers

7


The first pure and simple form can be obtained with a Dictionary

var casa = new Dictionary<string, object>();
casa.Add("cor", "verde");
casa.Add("tamanho", 2000);
var cor = casa["cor"];
var tamanho = casa["tamanho"];

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

I would avoid doing this since the object is left without typing. The first type of the structure indicates the type of the key. In the case string falls well. Since the value type can count several types, then you have to generalize and use object. That is, every entry in the dictionary will accept any value.

Another possible solution is to use the ExpandoObject that gives dynamism and can access with the two syntaxes (not simultaneously):

dynamic obj = new ExpandoObject();
obj.cor = "verde";
obj.tamanho = 2000;
WriteLine(obj.cor);
WriteLine(obj.tamanho);
var obj2 = (IDictionary<string,object>)obj;
WriteLine(obj2["cor"]);
WriteLine(obj2["tamanho"]);

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

Any solution declares a normal class and trying to access it this way is unnecessary. I might be doing reflection, but I’d probably be using the wrong tool for the problem.

  • What’s wrong with the answer?

  • My understanding was that he wants to string the properties of an object, not a key value structure.

  • 7

    But your understanding may be wrong. If you are not sure it is better not to vote. Ask him for clarification. From what I understand he voted for the answer, so he thought it was good.

  • 3

    @Mfedatto And with the acceptance of the AP, it seems that my understanding is correct. Don’t distribute negative because you understand something different. The negative is for the wrong things. I think the other answers give confusing solutions and probably do not meet what the AP wants, at least not simply. Not so I will deny them.

  • I agree with your point of view. I withdrew the negative.

6

You can use indexers as an example of the Microsoft documentation itself (https://msdn.microsoft.com/pt-br/library/2549tw02.aspx):

class Program
    {
        static void Main(string[] args)
        {
            List<Casa> lstCasas = new List<Casa>()
            {
                new Casa("Azul", 50),
                new Casa("Amarela", 70),
                new Casa("Branca", 90)
            };

            foreach (Casa _casa in lstCasas)
            {
                Console.WriteLine("Casa cor: {0}, tamanho: {1}", _casa["cor"], _casa["tamanho"]);
            }
            Console.Read();

            Casa _casaTemp = lstCasas[0];
            Console.WriteLine("Exception" + _casaTemp["Erro"]);
        }
    }

    public class Casa
    {
        private string cor;
        private int tamanho;

        public Casa(string _cor, int _tamanho)
        {
            this.cor = _cor;
            this.tamanho = _tamanho;
        }

        public object this[string strCampo]
        {
            get
            {
                switch (strCampo.ToLower())
                {
                    case "cor":
                        return this.cor;
                    case "tamanho":
                        return this.tamanho;
                    default:
                        throw new ArgumentException("Propriedade inválida");
                }
            }
        }
    }

A more generic approach, as cited by @Cigano Morrison Mendez would be using Generics. As shown below, a caveat for this approach is that one should use properties and not attributes and the get methods of the properties should be public:

public class Casa
    {
        public string cor { get; private set; }
        public int tamanho { get; private set; }

        public Casa(string _cor, int _tamanho)
        {
            this.cor = _cor;
            this.tamanho = _tamanho;
        }

        public object this[string strCampo]
        {
            get
            {
                return GetValorPelaPropriedade(strCampo);
            }
        }

        private object GetValorPelaPropriedade(string strNomePropriedade)
        {

            PropertyInfo _propInfo = this.GetType().GetProperty(strNomePropriedade);

            if (_propInfo == null)
                throw new ArgumentException("Propriedade inválida");

            return _propInfo.GetValue(this, null);
        }
    }
  • 2

    Very interesting, but I think it would be great if public object this[string strCampo] implemented using more generic behavior. + 1.

  • 1

    It has how to use Reflection to get the property, I will adjust here

  • 1

    Now yes, I’d say that’s the best answer so far.

2

Just convert the object to dictionary. This answer has the method below that can serve well:

public static KeyValuePair<object, object> Cast<K, V>(this KeyValuePair<K, V> kvp)
{
    return new KeyValuePair<object, object>(kvp.Key, kvp.Value);
}

public static KeyValuePair<T, V> CastFrom<T, V>(Object obj)
{
    return (KeyValuePair<T, V>) obj;
}

public static KeyValuePair<object, object> CastFrom(Object obj)
{
    var type = obj.GetType();
    if (type.IsGenericType)
    {
        if (type == typeof (KeyValuePair<,>))
        {
            var key = type.GetProperty("Key");
            var value = type.GetProperty("Value");
            var keyObj = key.GetValue(obj, null);
            var valueObj = value.GetValue(obj, null);
            return new KeyValuePair<object, object>(keyObj, valueObj);
        }
    }

    throw new ArgumentException(" ### -> public static KeyValuePair<object, object> CastFrom(Object obj) : Erro : argumento obj deve ser do tipo KeyValuePair<,>");
}

Use:

var dicionario = CastFrom(objeto);

Or even this answer, who opinionated it best to be an extension of any object:

public static class ObjectToDictionaryExtension
{
    public static IDictionary<string, object> ToDictionary(this object source)
    {
        return source.ToDictionary<object>();
    }

    public static IDictionary<string, T> ToDictionary<T>(this object source)
    {
        if (source == null)
            ThrowExceptionWhenSourceArgumentIsNull();

        var dictionary = new Dictionary<string, T>();
        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(source))
            AddPropertyToDictionary<T>(property, source, dictionary);
        return dictionary;
    }

    private static void AddPropertyToDictionary<T>(PropertyDescriptor property, object source, Dictionary<string, T> dictionary)
    {
        object value = property.GetValue(source);
        if (IsOfType<T>(value))
            dictionary.Add(property.Name, (T)value);
    }

    private static bool IsOfType<T>(object value)
    {
        return value is T;
    }

    private static void ThrowExceptionWhenSourceArgumentIsNull()
    {
        throw new ArgumentNullException("source", "Unable to convert object to a dictionary. The source object is null.");
    }
}

Use:

var dicionario = objeto.ToDictionary();
  • My understanding was that he wants to string the properties of an object, not a key value structure.

  • 1

    Well. You need to convert to a dictionary first. Through the native object there is no way.

  • Has with Reflection.

  • 4

    Good, then put your answer. I look forward to knowing how.

  • 1

    Done. Full and functional example posted as response.

1

To access the properties or methods of an object you need to use Reflection. You can even develop a hybrid class by encapsulating a key-value structure (Dictionary) to store values by name and implement properties Cor and Tamanho assigning and retrieving values through the keys, but the technically most responsive solution to your question is using Reflection. Follow a functional example that meets your need:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Casa casa = new Casa() { Cor = "Verde", Tamanho = 2000 };
            Wrapper wrapperCasa = new Wrapper(casa);

            wrapperCasa.SetPropetyValue<string>("Cor", "Vermelho");
            wrapperCasa.SetPropetyValue<int>("Tamanho", 2500);

            Console.WriteLine(wrapperCasa.GetPropetyValue<string>("Cor"));
            Console.WriteLine(wrapperCasa.GetPropetyValue<int>("Tamanho").ToString());
        }
    }

    class Casa
    {
        public string Cor { get; set; }
        public int Tamanho { get; set; }
    }

    class Wrapper
    {
        private object obj { get; set; }
        private Type tipo { get; set; }

        public Wrapper(object obj)
        {
            this.obj = obj;
            this.tipo = obj.GetType();
        }

        public void SetPropetyValue(string prop, object value)
        {
            this.SetPropetyValue<object>(prop, value);
        }

        public void SetPropetyValue<T>(string prop, T value)
        {
            this.GetPropertyInfo(prop).SetValue(this.obj, value, null);
        }

        public object GetPropetyValue(string prop)
        {
            return GetPropetyValue<object>(prop);
        }

        public T GetPropetyValue<T>(string prop)
        {
            return (T)this.GetPropertyInfo(prop).GetValue(this.obj, null);
        }

        private PropertyInfo GetPropertyInfo(string propriedade)
        {
            return this.tipo.GetProperty(propriedade);
        }
    }
}

I created an encapsulator (Wrapper) only to facilitate the use, because what actually happens is the use of the main object (Casa) without typing, such as a object, and use Reflection with an object Type to invoke the desired methods and properties.

Browser other questions tagged

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