Как получить список объектов интерфейса типа из xml - PullRequest
1 голос
/ 10 июля 2019

Как я могу получить List<IntrfaceType> из xml:

<?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 : IRule и AutoStart, NoMore, UnExpectedCrush : Rule, поэтомуЯ хочу получить Rule[], а затем преобразовать его List<IRule>, но Deserialize возвращает пустой массив.Поэтому, пожалуйста, помогите понять, что я делаю неправильно.

1 Ответ

0 голосов
/ 10 июля 2019

Хорошо, так что я думаю, что вы пытаетесь сделать это сопоставить все в:

   <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

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