Reflection C#, how does it work?

Asked

Viewed 513 times

10

I’m doing some tests with Reflection, I made this code on the basis of trial and error, so I didn’t understand how exactly it works.

This is the enum that I’m wearing:

public enum TipoDoAmbiente
{

    [System.Xml.Serialization.XmlEnumAttribute("1")]
    Item1,


    [System.Xml.Serialization.XmlEnumAttribute("2")]
    Item2,
}

The method propriedade.GetValue(objeto, null); returns the value of enum, in the case of this test that I made the value is item1. When I make a debug and stop at the itemEnum nothing more than the value itself appears.

I take this value and move on to the next methods, my doubt is how the rest of the code "discovers" the type and member information if I’m just passing the value item1?

           Type tipo = objeto.GetType();
           foreach (PropertyInfo propriedade in tipo.GetRuntimeProperties())
            {
                Type tipoBase = propriedade.PropertyType.BaseType;

                if (tipoBase.Name == "Enum")
                {
                    var itemEnum = propriedade.GetValue(objeto, null);
                    var valorEnum= (Enum)itemEnum;
                    var infoEnum = valorEnum.GetType().GetMember(propriedade.GetValue(objeto, null).ToString()).FirstOrDefault();
                    var EnumAttribute = infoEnum.GetCustomAttribute<XmlEnumAttribute>().Name;

                }


            }

I’m testing the deserialization of an XML, and I take the object that was generated, that object that is used in the code.

What left me more doubtful is that there are several enums with equal values, for example item1.

But only passing the value item1 for the code

var infoEnum = valorEnum.GetType().GetMember(propriedade.GetValue(objeto, null).ToString()).FirstOrDefault();

it returns the class and property to which it belongs.

  • Just want to know how it works internally? Or do you have some difficulty with what you’re doing? See if this helps: http://answall.com/q/13089/101

  • It would be internally, but I’m also learning, so I have difficulty. But I’d really like to know how the hell that works, because I only passed the value of Enum and it still works. Even though I create two enums with equal values, yet he "discovers" who he is.

  • I don’t know how to begin to answer, the question is very open. I can answer one thing and be what you want. The answer I showed help in any way? Is there anything else you need to know? Try to make the question a little more specific. como o resto do código "descobre" o tipo e as informações do membro se só estou passando o o valor item1? That’s not very clear. What is this example of reflection code doing there? Try to make these things come together and make sense.

  • @bigown, edited the question, see if it got less confused, and if it is possible you help me, I will be very grateful. I read the answer you showed.

  • 1

    I’ll try to answer something, just finish something here.

  • I didn’t understand it either... even with this edition.

  • Just like Overview: the . Net has managed memory, this means that every thing in memory is associated with the metadata of the type to which it belongs. It is the memory manager that does this. So when it is called xpto.GetType() the associated metadata is returned so you can consult.

  • I will try, but this code is too loose, it will be almost a kick. As the question is not very clear will not be able to complain. Ideally it would be better if you had made a [mcve] to show what you are having trouble understanding. Show what you thought, explain better what you didn’t understand. The edition helped a little, but gave more margin. Something was just a repetition of what I had before.

Show 3 more comments

2 answers

10


The ideal to explain about this would be interesting a deeper understanding about the functioning of computers, compilers, executables and other fundamentals of computing, but I will try not to be too technical, I run the risk of being a little vague.

Metadata

The . NET was created to be information-rich for the programmer. When the compiler creates a code he adds a series of metadata about that code. It’s like a database about its own code.

Then there is a data structure with lots of information about all the existing data types in your application (the types you created or the types of libraries used). These structures in general have informative and indicative texts of the relationship of each data with other data.

You can put custom information in that metadata. There are examples of how they work and information available in the metadata in the previous question. You can even create your own custom attributes.

Reflection

The reflection system is a set of algorithms to retrieve that information that is there next to your code. These are the methods you are using. If you are interested in more details already have a question about it.

The first step is the GetType() which is a method available in all objects of .NET. It takes the object passed to it, in the case of the example is valorEnum. This object has a pointer to its type (simply, the exact way may vary). So instead of this pointer, it has the basic structure of the type and where are its metadata. These metadata are organized into a complex object called Type (you can see all its details in the documentation). There is a data tree about the type. It is several different information.

An enumeration has some members. Somewhere in that object is stored which are the members. The compiler put everything he needed there. The method GetMembers() grabs all members of the type. All the same, even some that are not what you want. Of course you have to filter this.

If you want a specific desired you can call the method GetMember(). In case you need to pass some information identifying that member. Something on propriedade help define this. You are using the method GetValue() to obtain the desired object.

The return of GetMember() will provide all necessary information in a array object MemberInfo. The first of these items is the desired and the LINQ method FirstOrDefault() makes him the final result.

Example

I made a code that takes the data you want in a simple way (I used the same simple code that I passed on previous answer and you had not liked it, this time I did step by step).

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

  • Thank you for your attention, this piece of metadata has helped me a lot.

6

Before I start answering you, it’s important to explain what this code you put in the question is for. I set up a Fiddle to explain how it converts an object to XML.

We declare a class:

public class TesteClasse 
{
    public TipoDoAmbiente TipoDoAmbiente { get; set; }
}

We instantiate the class with a value of TipoDoAmbiente:

var classe = new TesteClasse { TipoDoAmbiente = TipoDoAmbiente.Item2 };

We also instantiated a XML serializer and a special object, XmlWriter, which receives the conversion of an object into XML by the serializer. To write the conversion result, this XmlWriter needs an object of streaming specialized (written in some type of memory, for example memory or disk). For example, I used StringWriter:

var xmlSerializer = new XmlSerializer(typeof(TesteClasse));
var stringWriter = new StringWriter();
var xmlWriter = XmlWriter.Create(stringWriter);

Recapping:

  1. Convert a C# object to XML;
  2. Write the object to another object that formats XML;
  3. Convert XML to a string XML.

The result of XML is:

<?xml version="1.0" encoding="utf-16"?>
<TesteClasse xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <TipoDoAmbiente>2</TipoDoAmbiente>
</TesteClasse>

Notice that I defined TipoAmbiente as Tipo2, but the XML serializer wrote only as 2, according to its definition of attribute.

I’ll do the reverse now. From a string XML and convert it to the object, but this time using not a XmlWriter, but a XmlReader and, similarly, a StringReader (Fiddle here)

    var xml = "<?xml version=\"1.0\" encoding=\"utf-16\"?><TesteClasse xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><TipoDoAmbiente>2</TipoDoAmbiente></TesteClasse>";
    var xmlSerializer = new XmlSerializer(typeof(TesteClasse));
    TesteClasse testeClasse = (TesteClasse)xmlSerializer.Deserialize(XmlReader.Create(new StringReader(xml)));
    Console.WriteLine(testeClasse.TipoDoAmbiente);

The example will write in console Item2.

Now, to your questions.

The method propriedade.GetValue(objeto, null); returns the value of Enum, in the case of this test that I made the value is item1. When I make a debug and stop at the itemEnum nothing more than the value itself appears.

I take this value and move on to the next methods, my doubt is how the rest of the code "discovers" the type and member information if I’m just passing the value item1?

If you also want to pass the member’s type and information, it’s not just getting the value of it that will happen. You also need to retrieve the object PropertyInfo related to the property you want to recover the value. This you have already done here:

foreach (PropertyInfo propriedade in tipo.GetRuntimeProperties()) { ... }

But only passing the value item1 for the code var infoEnum = valorEnum.GetType().GetMember(propriedade.GetValue(objeto, null).ToString()).FirstOrDefault();

it returns the class and property to which it belongs.

Well, this is very wrong. I think what you want is to retrieve an object for the value of TipoDeAmbiente from what I understand.

In this case, System.Linq better resolve the situation for you:

// Estou supondo que você desserializou um XML em uma lista, tipo List<TesteClasse>. 
var propertiesTipoDeAmbiente = typeof(TesteClasse).GetProperties().Where(p => p.PropertyType == TipoDeAmbiente);
foreach (var propriedade in propertiesTipoDeAmbiente)
{
    foreach (var elemento in lista)
    {
        if (((TipoDeAmbiente)propriedade.GetValue(elemento, null)) == TipoDeAmbiente.Item1)
            yield return elemento; // Isto aqui acumula tudo em um IEnumerable<TesteClasse>. 
    }
}

Last thing

This is pretty slow. Use this Nuget package to read this with a decent performance.

Browser other questions tagged

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