如何从xml获取接口类型的对象列表

时间:2019-07-10 10:02:08

标签: c# xml-serialization

如何从xml获取List<IntrfaceType>

<?xml version="1.0" encoding="utf-8" ?>
 <processSettings>
   <processName>chrome.exe</processName>
   <location>L1</location>
   <watch>true</watch>
   <rules>
        <autoStart></autoStart>
        <noMore></noMore>
        <unExpectedCrush></unExpectedCrush>
    </rules>
 </processSettings>

我尝试过这样:

[XmlRootAttribute("rules", Namespace = "", IsNullable = false)]
public class Rules
{
    [XmlArrayItem("autoStart", Type = typeof(AutoStart)),
     XmlArrayItem("noMore", Type = typeof(NoMore)),
     XmlArrayItem("unExpectedCrush", Type = typeof(UnExpectedCrush))]
    public Rule[] RuleItems;

XmlSerializer ruleSerializer = new XmlSerializer(typeof(Rule[]), new XmlRootAttribute("rules"));
        Rule[] rules = (Rule[])ruleSerializer.Deserialize(config.Rules.CreateReader());

在这种情况下,Rule : IRuleAutoStart, NoMore, UnExpectedCrush : Rule,所以我想获得Rule[]然后对其进行转换List<IRule>,但是Deserialize返回一个空数组。因此,请帮助了解我做错了什么。

1 个答案:

答案 0 :(得分:0)

好,所以我认为您想做的是将所有内容映射到:

   <rules>
        <autoStart></autoStart>
        <noMore></noMore>
        <unExpectedCrush></unExpectedCrush>
    </rules>

到规则列表。而且,您只是尝试直接在XML上运行反序列化,并假设它可以将rules的子代神奇地映射到IRule

如果您确实想要规则列表,则首先必须以某种方式提取信息。通过将XML映射到类型化的对象中,最容易做到这一点。因此,在您的情况下,而不是结束列表,我将创建一个映射对象:

public class Rules
{
    public string AutoStart { get; set; }
    public string NoMore { get; set; }
    public string UnExpectedCrush { get; set; }
}

请执行以下操作:

(Rules) ruleSerializer.Deserialize(config.Rules.CreateReader());

现在,您有一个对象,其中包含所有规则。从那时起,您可以将属性重新映射到规则列表中。但是我认为,对于可能读取您代码的其他人来说,拥有一个实际的Rules对象(在其中命名规则)通常会更清楚。那只是我的两分钱。

或者::如果您可以控制XML,则可以执行以下操作:

 <processSettings>
   <processName>chrome.exe</processName>
   <location>L1</location>
   <watch>true</watch>
   <rules>
        <rule>autoStart</rule>
        <rule>noMore</rule>
        <rule>unExpectedCrush</rule>
    </rules>
 </processSettings>

并将其反序列化为规则列表:

(List<Rule>)deserializer.Deserialize(config.Rules.CreateReader());

然后您就有了可以转换为接口版本的规则列表。

但这会更改XML,因此它假定您对此具有控制权。

编辑::从List<Rule>List<IRule>

因此,如果您能够获得List<Rule>的列表,并且Rule具有相关的接口。然后,您可以转换您的List<Rule>

List<Rule> rules = new List<Rule>();
List<IRule> iRules = rules.ToList<IRule>();

根据此答案StackOverflow answer

EDIT2 :将XElement序列化为规则列表:

好的,所以我仍然很难理解为什么您需要将这些规则映射到对象而不是带有值的规则。我要说的是一个包含一个字符串的规则列表,该字符串表明该规则将使您的生活更轻松。然后,您只需要进行字符串比较即可查看您有什么规则。

因此,我认为这将解决您的问题:

public List<IRule> GetListOfRules()
{
    var rulesElement = XElement.Parse(@"<rules>
        <autoStart></autoStart>
        <noMore></noMore>
        <unExpectedCrush></unExpectedCrush>
    </rules>");

    var listOfRulesFromElement = 
        rulesElement.Elements().Select(d => new Rule { RuleName = d.Name.LocalName }).ToList<IRule>();

    return listOfRulesFromElement;
}

public class Rule : IRule
{
    public string RuleName { get; set; }
    public string GetRule()
    {
        return RuleName;
    }
}

public interface IRule
{
    string GetRule();
}

使用此代码,您在结构和规则之间没有任何硬耦合。您只需将新规则添加到XML元素中,它将自动添加到规则列表中。然后,您可以检查规则列表,并根据RuleName查看其中有哪些规则。我希望这就是你想要的。

编辑3 :键入的映射:

如果您需要类型映射,建议您使用一个枚举:

public List<IRule> GetListOfRules()
{
    var rulesElement = XElement.Parse(@"<rules>
        <autoStart></autoStart>
        <noMore></noMore>
        <unExpectedCrush></unExpectedCrush>
    </rules>");

    var listOfRulesFromElement = 
        rulesElement.Elements().Select(d =>
        {
            var parsed = Enum.TryParse(d.Name.LocalName, out RuleType ruleName);
            if (!parsed)
                ruleName = RuleType.UnmappedRule;
            return new Rule {RuleName = ruleName};
        }).ToList<IRule>();

    return listOfRulesFromElement;
}

public class Rule : IRule
{
    public RuleType RuleName { get; set; }
    public RuleType GetRule()
    {
        return RuleName;
    }
}

public enum RuleType
{
    UnmappedRule,
    AutoStart,
    NoMore,
    UnExpectedCrush
}

public interface IRule
{
    RuleType GetRule();
}