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

1

Is it possible to produce simpler code for this function without changing 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's 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() + "\"";
    
asked by anonymous 02.10.2017 / 20:44

1 answer

1

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

Another change is that I would join the two methods into one using tuples avoiding exceptions, changes between verification and use, outside of code duplication. You can only use the boolean name to be true, otherwise it is invalid. I did this because usage indicated that this was the intention.

I did not understand some things in this code, including looping another loop to scan the same data. So I simplified this.

I made a validation because what is passed may not be an enumeration. Too bad C # does not let it restrict this in code at compile time. It makes sense to be an exception because it is a programming error. Never capture her.

I went straight into the type members rather than the enumeration for simplicity.

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

I also used pattern matching .

I've 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 placed GitHub for future reference . As you use newer features, these online IDEs do not compile this code, so I did not post it, but I tested it on VS and it's ok.

If you do not want to use tuple you can use a out parameter, just like a TryParse() . You can also take pattern matching and make the code more verbose.

    
03.10.2017 / 03:58