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

How to get a list of objects which are interface type from xml

如何从 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 returns一个空数组。所以请帮助理解我做错了什么。

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

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

到规则列表。你只是想 运行 直接在 XML 上反序列化,并假设它会神奇地将 rules 的 children 映射到 IRule.

如果你真的想要一个规则列表,你首先必须以某种方式提取信息。这最容易通过将 XML 映射到类型化的 object 来完成。因此,在您的情况下,我不会以列表结尾,而是进行映射 object:

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

所以做这样的事情:

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

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

或者: 如果您可以控制 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>();

取自这个答案Whosebug answer

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

好的,所以我仍然很难理解为什么您需要将这些规则映射到 object 而不是具有值的规则。我会说一个规则列表,其中包含一个字符串,说明它是哪种规则将使您的生活更轻松。然后你只需要进行字符串比较,看看你有什么规则。

所以我认为这将解决您的问题:

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();
}