Сопоставление значений xml с типом перечисления
мне нужно проанализировать XML-файл, который я получаю от сторонних объектов C#. Некоторые XML я получаю значения перечисления, которые я хочу хранить в перечислимый тип.
например, у меня есть следующий xsd xml-файла:
<xsd:simpleType name="brandstof">
<xsd:restriction base="xsd:string">
<!-- Benzine -->
<xsd:enumeration value="B" />
<!-- Diesel -->
<xsd:enumeration value="D" />
<!-- LPG/Gas -->
<xsd:enumeration value="L" />
<!-- LPG G3 -->
<xsd:enumeration value="3" />
<!-- Elektrisch -->
<xsd:enumeration value="E" />
<!-- Hybride -->
<xsd:enumeration value="H" />
<!-- Cryogeen -->
<xsd:enumeration value="C" />
<!-- Overig -->
<xsd:enumeration value="O" />
</xsd:restriction>
</xsd:simpleType>
Я хочу сопоставить это с перечислением, и я получил это далеко:
public enum Fuel
{
B,
D,
L,
E,
H,
C,
O
}
проблема в том, что xml может содержать значение 3
который я не могу поместить в тип перечисления. Есть ли какое-либо решение поставить это значение в перечислении.
Я также могу получить другие значения с помощью -
или /
в них и которые я хочу поместить в тип перечисления.
Предложения Anu приветствуются!
4 ответов
вы можете проанализировать значение атрибута xml обратно в тип перечисления с помощью:
var value = Enum.Parse(typeof(Fuel), "B");
но я не думаю, что вы получите очень далеко с вашими "особыми" значениями (3
, a/
etc.).
Почему бы вам не определить свое перечисление как
enum Fuel
{
Benzine,
Diesel,
// ...
Three,
ASlash,
// ...
}
и написать статический метод для преобразования строки к члену enum?
одна вещь, которую вы могли бы изучить для реализации такого метода, - это добавить пользовательские атрибуты к членам перечисления, содержащим их строковое представление - если значение не имеет точного аналога в перечислении, найдите элемент с атрибутом.
создать такой атрибут легко:
/// <summary>
/// Simple attribute class for storing String Values
/// </summary>
public class StringValueAttribute : Attribute
{
public string Value { get; private set; }
public StringValueAttribute(string value)
{
Value = value;
}
}
и затем вы можете использовать их в ваших перечислений:
enum Fuel
{
[StringValue("B")]
Benzine,
[StringValue("D")]
Diesel,
// ...
[StringValue("3")]
Three,
[StringValue("/")]
Slash,
// ...
}
эти два метода помогут вам разобрать строку в член перечисления по вашему выбору:
/// <summary>
/// Parses the supplied enum and string value to find an associated enum value (case sensitive).
/// </summary>
public static object Parse(Type type, string stringValue)
{
return Parse(type, stringValue, false);
}
/// <summary>
/// Parses the supplied enum and string value to find an associated enum value.
/// </summary>
public static object Parse(Type type, string stringValue, bool ignoreCase)
{
object output = null;
string enumStringValue = null;
if (!type.IsEnum)
{
throw new ArgumentException(String.Format("Supplied type must be an Enum. Type was {0}", type));
}
//Look for our string value associated with fields in this enum
foreach (FieldInfo fi in type.GetFields())
{
//Check for our custom attribute
var attrs = fi.GetCustomAttributes(typeof (StringValueAttribute), false) as StringValueAttribute[];
if (attrs != null && attrs.Length > 0)
{
enumStringValue = attrs[0].Value;
}
//Check for equality then select actual enum value.
if (string.Compare(enumStringValue, stringValue, ignoreCase) == 0)
{
output = Enum.Parse(type, fi.Name);
break;
}
}
return output;
}
и пока я на нем: вот наоборот;)
/// <summary>
/// Gets a string value for a particular enum value.
/// </summary>
public static string GetStringValue(Enum value)
{
string output = null;
Type type = value.GetType();
if (StringValues.ContainsKey(value))
{
output = ((StringValueAttribute) StringValues[value]).Value;
}
else
{
//Look for our 'StringValueAttribute' in the field's custom attributes
FieldInfo fi = type.GetField(value.ToString());
var attributes = fi.GetCustomAttributes(typeof(StringValueAttribute), false);
if (attributes.Length > 0)
{
var attribute = (StringValueAttribute) attributes[0];
StringValues.Add(value, attribute);
output = attribute.Value;
}
}
return output;
}
украшения с XmlEnum
атрибут: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlenumattribute.aspx
public enum Fuel
{
[XmlEnum("B")]
Benzine,
[XmlEnum("D")]
Diesel,
[XmlEnum("L")]
LpgGas,
[XmlEnum("3")]
LpgG3,
[XmlEnum("E")]
Elektrisch,
[XmlEnum("H")]
Hybride,
[XmlEnum("C")]
Cryogeen,
[XmlEnum("O")]
Overig
}
почему вы не можете разобрать строку
[XmlAttribute("brandstof")]
public string FuelTypeString
{
get { return fuel.ToString(); }
set
{
fuel = (Fuel)System.Enum.Parse(typeof(Fuel), value);
}
}
[XmlIgnore()]
public Fuel FuelType
{
get { return fuel; }
set { fuel = value; }
}
таким образом, вы действительно сериализуете его как строку.
Я создал класс, который обрабатывает это:
class EnumCreator
{
public static Type CreateEnum(List<string> AValues)
{
// Get the current application domain for the current thread.
AppDomain currentDomain = AppDomain.CurrentDomain;
// Create a dynamic assembly in the current application domain,
// and allow it to be executed and saved to disk.
AssemblyName aName = new AssemblyName("TempAssembly");
AssemblyBuilder ab = currentDomain.DefineDynamicAssembly(
aName, AssemblyBuilderAccess.RunAndSave);
// Define a dynamic module in "TempAssembly" assembly. For a single-
// module assembly, the module has the same name as the assembly.
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");
// Define a public enumeration with the name "Elevation" and an
// underlying type of Integer.
EnumBuilder eb = mb.DefineEnum("EnumValues", TypeAttributes.Public, typeof(int));
// Define two members, "High" and "Low".
foreach (string v in AValues)
{
eb.DefineLiteral(v, AValues.IndexOf(v));
}
// Create the type and save the assembly.
Type finished = eb.CreateType();
return finished;
}
}
вы должны сначала прочитать xml-файл и поместить значения в список, вы можете сделать это, например, с объектом XElement.
//редактирование: Вот так:
XElement xml = XElement.parse("file.xml");
List<string> enumItems = new List<string>();
foreach(XElement row in xml.Element("xsd:simpleType").Element("xsd:restriction").Elements())
{
enumItems.Add(row.Attribute("value").Value);
}
Type Fuel = EnumCreator.CreatEnum(enumItems);