Check if there is value in the enumeration by the attribute and return its value

Asked

Viewed 992 times

1

It is possible to produce simpler code for this function without changing the enum?

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.6.1055.0")]
[System.SerializableAttribute()]
public enum Velocidade
{

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("01")]
    Baixa,

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("02")]
    Normal,

    /// <remarks/>
    [System.Xml.Serialization.XmlEnumAttribute("03")]
    Rapida,

}

Below is a method to check if the value exists:

private bool EnumHasValue(Type pTipoDoEnum, string valorDoEnum)
{

    foreach (var val in Enum.GetValues(pTipoDoEnum))
    {
        var member = pTipoDoEnum.GetMember(val.ToString()).FirstOrDefault();
        var attribute = member.GetCustomAttributes(false).OfType<XmlEnumAttribute>().FirstOrDefault();
        if (valorDoEnum == attribute.Name)
        {
            return true;
        }
    }
    return false;
}

In the method below the value corresponding to string is found

private object EnumFromString(Type pTipoDoEnum, string valorDoEnum)
{

    foreach (var val in Enum.GetValues(pTipoDoEnum))
    {
        var member = pTipoDoEnum.GetMember(val.ToString()).FirstOrDefault();
        var attribute = member.GetCustomAttributes(false).OfType<XmlEnumAttribute>().FirstOrDefault();
        if (valorDoEnum == attribute.Name)
        {
            return val;
        }                
    }
    throw new Exception("Não existe o valor " + Text + " para o tipo " + pTipoDoEnum.ToString() + ". Utilize o método EnumHasValue antes da conversão.");
}

Here is how the method is called:

string text = "02";

Velocidade velocidade = new Velocidade();
if (EnumHasValue(typeof(Velocidade),text)) velocidade = (Velocidade)EnumFromString(typeof(Velocidade), text);

// O resultado é: "Normal"
textBox1.Text = "O resultado é: \"" + velocidade.ToString() + "\"";
  • Would a simple and objective extension method no longer solve?

  • Did the answer solve your question? Do you think you can accept it? See [tour] if you don’t know how you do it. This would help a lot to indicate that the solution was useful to you. You can also vote on any question or answer you find useful on the entire site.

1 answer

1

The first major change is to make the method generic and not leak abstraction.

Another change is that I would put the two methods together in one using tuples avoiding exceptions, changes between verification and use, apart from code duplicity. You can only use the boolean name is true, otherwise it is invalid. I did this because the use indicated that this was the intention.

I didn’t understand some things of this code, including making a loop within another loop to scan the same data. So I simplified this.

I did a validation because what is passed may not be an enumeration. Too bad C# doesn’t let you restrict this in code at compile time. Then it makes sense to be an exception because it’s a programming error. Never capture it.

I went straight to the members of the type and not the enumeration to simplify.

I improved the names of the variables and the method itself.

I also used Pattern matching.

I simplified other things.

I would do so:

using System;
using static System.Console;
using System.Xml.Serialization;

public class Program {
    public static void Main() {
        (var ok, var nome) = EnumFromXmlAttribute<Velocidade>("02");
        if (ok) WriteLine($"O resultado é: \"{nome}\"");
        (ok, nome) = EnumFromXmlAttribute<Velocidade>("05");
        if (ok) WriteLine($"O resultado é: \"{nome}\"");
    }
    private static (bool, T) EnumFromXmlAttribute<T>(string texto) {
        var type = typeof(T);
        if (!type.IsEnum) throw new ArgumentException("O tipo precisa ser uma enumeração");
        foreach (var item in type.GetFields())  {
            if (Attribute.GetCustomAttribute(item, typeof(XmlEnumAttribute)) is XmlEnumAttribute attribute && texto == attribute.Name)
                return (true, (T)item.GetValue(null));
        }
        return (false, default(T));
    }
}

[System.SerializableAttribute()]
public enum Velocidade {
    [XmlEnumAttribute("01")] Baixa,
    [XmlEnumAttribute("02")] Normal,
    [XmlEnumAttribute("03")] Rapida,
}

I put in the Github for future reference. How do you use newer resources, these Ides online do not compile this code, so I did not post, but tested in VS and is ok.

If you do not want to use tuple you can use a parameter out, as it is in a TryParse(). You can also take the Pattern matching and make the code more verbose, I just don’t think it makes sense to avoid these things anymore.

Browser other questions tagged

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