Xml 挑战:你能用C#4.0让这个简单的函数更优雅吗

Xml 挑战:你能用C#4.0让这个简单的函数更优雅吗,xml,c#-4.0,Xml,C# 4.0,当我浏览我们的代码库时,我注意到了这个函数。它将IDictionary(参数-实例变量)转换为XML字符串 这只是我的好奇心:-) 那么,使用C#4.0编写的代码可以少得多吗?规则:除了.Net Framework BCL之外,没有外部LIB。 为了让它更具挑战性,我不在这里介绍输入字典规范,因为您应该能够从代码中找到它 public string ConvertToXml() { XmlDocument doc = new XmlDocument(); doc.LoadXml(

当我浏览我们的代码库时,我注意到了这个函数。它将
IDictionary
(参数-实例变量)转换为XML字符串

这只是我的好奇心:-)

那么,使用C#4.0编写的代码可以少得多吗?规则:除了.Net Framework BCL之外,没有外部LIB。

为了让它更具挑战性,我不在这里介绍输入字典规范,因为您应该能够从代码中找到它

public string ConvertToXml() {
    XmlDocument doc = new XmlDocument();
    doc.LoadXml("<?xml version='1.0' encoding='utf-8'?><sc/>");
    foreach (KeyValuePair<string, object> param in Parameters) {
        XmlElement elm = doc.CreateElement("pr");

        if (param.Value is int || param.Value is Int32 || param.Value is Int16 || param.Value is Int64) {
            elm.SetAttribute("tp", "int");
        } else if (param.Value is DateTime?){
            elm.SetAttribute("tp", "datetime");
        } else {
            elm.SetAttribute("tp", "string");
        }

        elm.SetAttribute("nm", param.Key);
        if (param.Value is DateTime?) {
            DateTime? dateTime = param.Value as DateTime?;
            elm.SetAttribute("vl", dateTime.Value.ToString("o"));
        } else{
            elm.SetAttribute("vl", param.Value.ToString());
        }
        doc.FirstChild.NextSibling.AppendChild(elm);
    }
    return doc.OuterXml;
}
公共字符串ConvertToXml(){
XmlDocument doc=新的XmlDocument();
doc.LoadXml(“”);
foreach(参数中的KeyValuePair参数){
XmlElement elm=doc.CreateElement(“pr”);
if(param.Value为int | | param.Value为Int32 | | param.Value为Int16 | | param.Value为Int64){
elm.SetAttribute(“tp”、“int”);
}else if(参数值是DateTime?){
elm.SetAttribute(“tp”、“日期时间”);
}否则{
elm.SetAttribute(“tp”、“字符串”);
}
elm.SetAttribute(“nm”,参数键);
如果(参数值是DateTime?){
DateTime?DateTime=参数值为DateTime?;
elm.SetAttribute(“vl”,dateTime.Value.ToString(“o”);
}否则{
SetAttribute(“vl”,param.Value.ToString());
}
文件FirstChild.NextSibling.AppendChild(elm);
}
返回doc.OuterXml;
}
让我补充一些想法

对我来说:

  • 少即是多,但简练是不好的
  • 更多的类型是好的,但琐碎的类型似乎很臭
  • 可重用性很好

考虑到新的要求,重新协商

  • 每个具体类型和XML生成逻辑本身的解耦转换细节
  • 通过向提供程序添加新工厂,可以轻松引入新的数据类型支持。当前支持的类型集受枚举成员的限制,但显然可以轻松地切换到其他类型选择器/标识符
  • 我必须同意jbtule的观点。Create()确实比构建的要好得多,以前从未使用过,很好的东西,谢谢
方法本身:

public string ConvertToXml(
    IDictionary<string, object> rawData, 
        Dictionary<TypeCode, Func<object, Tuple<string, string>>> transformationFactoryProvider) 
{
    XmlDocument doc = new XmlDocument();
    doc.LoadXml("<?xml version='1.0' encoding='utf-8'?><sc/>");

    if (rawData != null)
    {
        Func<object, Tuple<string, string>> defaultFactory = 
              (raw) => Tuple.Create("string", raw.ToString());

        foreach (KeyValuePair<string, object> item in rawData)
        {
            TypeCode parameterTypeCode = Type.GetTypeCode(item.Value.GetType());
            var transformationFactory = transformationFactoryProvider.ContainsKey(parameterTypeCode)
                                            ? transformationFactoryProvider[parameterTypeCode]
                                            : defaultFactory;

            var transformedItem = transformationFactory(item.Value);
            XmlElement xmlElement = doc.CreateElement("pr");
            xmlElement.SetAttribute("tp", transformedItem.Item1);
            xmlElement.SetAttribute("nm", item.Key);
            xmlElement.SetAttribute("vl", transformedItem.Item2);
            doc.FirstChild.NextSibling.AppendChild(xmlElement);
        }
    }

    return doc.OuterXml; 
}
// Transformation Factories
// Input: raw object
// Output: Item1: type name, Item2: value in the finally formatted string
Func<object, Tuple<string, string>> numericFactory = raw => Tuple.Create("int", raw.ToString());
Func<object, Tuple<string, string>> dateTimeFactory =
    raw => Tuple.Create("datetime", (raw as DateTime?).GetValueOrDefault().ToString("o"));

// Transformation Factory Provider
// Input: TypeCode
// Output: transformation factory for the given type
var transformationFactoryProvider =
    new Dictionary<TypeCode, Func<object, Tuple<string, string>>>
        {                        
            {TypeCode.Int16, numericFactory},
            {TypeCode.Int32, numericFactory},
            {TypeCode.Int64, numericFactory},
            {TypeCode.DateTime, dateTimeFactory}
        };

// Convert to XML given parameters
IDictionary<string, object> parameters = new Dictionary<string, object>
                         {
                                { "SOMEDATA", 12 },
                                { "INTXX", 23 },
                                { "DTTM", DateTime.Now },
                                { "PLAINTEXT", "Plain Text" },
                                { "RAWOBJECT", new object() },
                          };
string xmlParameters = this.ConvertToXml(parameters, transformationFactoryProvider);
公共字符串convertXML(
索引原始数据,
字典转换FactoryProvider)
{
XmlDocument doc=新的XmlDocument();
doc.LoadXml(“”);
if(rawData!=null)
{
Func defaultFactory=
(raw)=>Tuple.Create(“string”,raw.ToString());
foreach(rawData中的KeyValuePair项)
{
TypeCode参数TypeCode=Type.GetTypeCode(item.Value.GetType());
var transformationFactory=transformationFactoryProvider.ContainsKey(参数类型代码)
?transformationFactoryProvider[参数类型代码]
:默认工厂;
var transformedItem=transformationFactory(项值);
xmlement xmlement=doc.CreateElement(“pr”);
SetAttribute(“tp”,transformedItem.Item1);
SetAttribute(“nm”,item.Key);
SetAttribute(“vl”,transformedItem.Item2);
doc.FirstChild.NextSibling.AppendChild(xmlElement);
}
}
返回doc.OuterXml;
}

如何使用示例:

public string ConvertToXml(
    IDictionary<string, object> rawData, 
        Dictionary<TypeCode, Func<object, Tuple<string, string>>> transformationFactoryProvider) 
{
    XmlDocument doc = new XmlDocument();
    doc.LoadXml("<?xml version='1.0' encoding='utf-8'?><sc/>");

    if (rawData != null)
    {
        Func<object, Tuple<string, string>> defaultFactory = 
              (raw) => Tuple.Create("string", raw.ToString());

        foreach (KeyValuePair<string, object> item in rawData)
        {
            TypeCode parameterTypeCode = Type.GetTypeCode(item.Value.GetType());
            var transformationFactory = transformationFactoryProvider.ContainsKey(parameterTypeCode)
                                            ? transformationFactoryProvider[parameterTypeCode]
                                            : defaultFactory;

            var transformedItem = transformationFactory(item.Value);
            XmlElement xmlElement = doc.CreateElement("pr");
            xmlElement.SetAttribute("tp", transformedItem.Item1);
            xmlElement.SetAttribute("nm", item.Key);
            xmlElement.SetAttribute("vl", transformedItem.Item2);
            doc.FirstChild.NextSibling.AppendChild(xmlElement);
        }
    }

    return doc.OuterXml; 
}
// Transformation Factories
// Input: raw object
// Output: Item1: type name, Item2: value in the finally formatted string
Func<object, Tuple<string, string>> numericFactory = raw => Tuple.Create("int", raw.ToString());
Func<object, Tuple<string, string>> dateTimeFactory =
    raw => Tuple.Create("datetime", (raw as DateTime?).GetValueOrDefault().ToString("o"));

// Transformation Factory Provider
// Input: TypeCode
// Output: transformation factory for the given type
var transformationFactoryProvider =
    new Dictionary<TypeCode, Func<object, Tuple<string, string>>>
        {                        
            {TypeCode.Int16, numericFactory},
            {TypeCode.Int32, numericFactory},
            {TypeCode.Int64, numericFactory},
            {TypeCode.DateTime, dateTimeFactory}
        };

// Convert to XML given parameters
IDictionary<string, object> parameters = new Dictionary<string, object>
                         {
                                { "SOMEDATA", 12 },
                                { "INTXX", 23 },
                                { "DTTM", DateTime.Now },
                                { "PLAINTEXT", "Plain Text" },
                                { "RAWOBJECT", new object() },
                          };
string xmlParameters = this.ConvertToXml(parameters, transformationFactoryProvider);
//转换工厂
//输入:原始对象
//输出:Item1:类型名称,Item2:最终格式化字符串中的值
Func numericFactory=raw=>Tuple.Create(“int”,raw.ToString());
Func dateTimeFactory=
raw=>Tuple.Create(“datetime”,raw为datetime?).GetValueOrDefault().ToString(“o”);
//转换工厂提供者
//输入:类型代码
//输出:给定类型的转换工厂
var transformationFactoryProvider=
新词典
{                        
{TypeCode.Int16,numericFactory},
{TypeCode.Int32,numericFactory},
{TypeCode.Int64,numericFactory},
{TypeCode.DateTime,dateTimeFactory}
};
//将给定参数转换为XML
IDictionary参数=新字典
{
{“SOMEDATA”,12},
{“INTXX”,23},
{“DTTM”,DateTime.Now},
{“纯文本”,“纯文本”},
{“RAWOBJECT”,新对象()},
};
字符串xmlParameters=this.convertXML(参数,transformationFactoryProvider);

使用LINQ到XML可以使编写变得非常简单。如果您有选择的话,您更喜欢这个而不是标准的XML库

我认为这应该相当于:

public static string ToXmlString(this IDictionary<string, object> dict)
{
    var doc = new XDocument(new XElement("sc", dict.Select(ToXElement)));

    using (var writer = new Utf8StringWriter())
    {
        doc.Save(writer); // "hack" to force include the declaration
        return writer.ToString();
    }
}

class Utf8StringWriter : StringWriter
{
    public override Encoding Encoding { get { return Encoding.UTF8; } }
}

static XElement ToXElement(KeyValuePair<string, object> kvp)
{
    var value = kvp.Value ?? String.Empty;

    string typeString;
    string valueString;
    switch (Type.GetTypeCode(value.GetType()))
    {
    case TypeCode.Int16:
    case TypeCode.Int32:
    case TypeCode.Int64:
        typeString = "int";
        valueString = value.ToString();
        break;
    case TypeCode.DateTime:
        typeString = "datetime";
        valueString = ((DateTime)value).ToString("o");
        break;
    default:
        typeString = "string";
        valueString = value.ToString();
        break;
    }

    return new XElement("pr",
        new XAttribute("tp", typeString),
        new XAttribute("nm", kvp.Key),
        new XAttribute("vl", valueString));
}
公共静态字符串ToXmlString(此IDictionary dict)
{
var doc=新的XDocument(新的XElement(“sc”,dict.Select(ToXElement));
使用(var writer=new Utf8StringWriter())
{
doc.Save(writer);/“hack”强制包含声明
返回writer.ToString();
}
}
类Utf8StringWriter:StringWriter
{
公共重写编码{get{return Encoding.UTF8;}}
}
静态元素(KeyValuePair kvp)
{
var value=kvp.value??String.Empty;
字符串类型字符串;
字符串值字符串;
开关(Type.GetTypeCode(value.GetType()))
{
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
typeString=“int”;
valueString=value.ToString();
打破
案例类型代码.DateTime:
typeString=“datetime”;
valueString=((日期时间)值).ToString(“o”);
打破
违约:
typeString=“string”;
valueString=value.ToString();
打破
}
返回新的XElement(“pr”,
新XAttribute(“tp”,类型字符串),
新XAttribute(“nm”,kvp.Key),
新的XAttribute(“vl”,valueString));
}
注意,检查
public string ConvertToXml()
{
    var doc = new XDocument(
        new XElement("sd",
            Parameters.Select(param =>
                new XElement("pr",
                    new XAttribute("tp", GetTypeName((dynamic)param.Value)),
                    new XAttribute("nm", param.Key),
                    new XAttribute("vl", GetValue((dynamic)param.Value))
                    )
                )
            )
        );
    return doc.ToString();
}
static string GetTypeName(long value)
{
    return "int";
}

static string GetTypeName(DateTime? value)
{
    return "datetime";
}

static string GetTypeName(object value)
{
    return "string";
}

static string GetValue(DateTime? value)
{
    return value.Value.ToString("o");
}

static string GetValue(object value)
{
    return value.ToString();
}
public string ConvertToXml()
{
    return new XElement("sc",
        Parameters.Select(param => CreateElement(param.Key, (dynamic)param.Value))
    ).ToString(SaveOptions.DisableFormatting);
}
XElement CreateElement(string key, object value)
{
    return CreateElement("string", key, value.ToString());
}

XElement CreateElement(string key, long value)
{
    return CreateElement("int", key, value.ToString());
}

XElement CreateElement(string key, DateTime value)
{
    return CreateElement("datetime", key, value.ToString("o"));
}
XElement CreateElement(string typename, string key, string value)
{
    return new XElement("pr",
        new XAttribute("tp", typename),
        new XAttribute("nm", key),
        new XAttribute("vl", value)
    );
}