遍历字典值

时间:2021-05-04 06:49:23

标签: c# dictionary yaml

嘿,我正在将一个 yaml 文件和(在运行程序之前我不知道结构)反序列化为 Dictionary<object, List<object>> 我如何遍历这个对象和值。这是我尝试过的。或者您有其他想法在不知道结构的情况下获取 yaml 文件的值,谢谢

var t = deserializer.ParseYamlTagByType(text);

foreach (KeyValuePair<object, List<object>> entry in t)
{
    foreach (Dictionary<object, object> item in entry.Value)
    {
        foreach (KeyValuePair<object, object> tag in item)
        {
            //List<object> value = (List<object>)tag.Value;
            foreach (var config in (List<object>)tag.Value)
            {
                Dictionary<object, object> test = (Dictionary<object, object>)config;
                foreach (KeyValuePair<object, object> configurationString in test)
                {
                    var tagname = configurationString.Key;
                    var tagvalue = configurationString.Value;
                }
            }
        }
    }
}

public Dictionary<object, List<object>> ParseYamlTagByType(string input)
{
    return this.deserializer.Deserialize<Dictionary<object, List<object>>>(input);
}

public class CalcYamlFile
{
   [YamlMember(Alias = "gc", ApplyNamingConventions = false)]
   public List<CalcTag> GcTag { get; set; }
}

public class CalcTag
{
   public Clean Clean { get; set; }
   public Dependencies Dependencies { get; set; }
   public Solution Solution { get; set; }
   public Test Test { get; set; }
}

public class Clean
{
  [Required]
  public object Location { get; set; }
  //Maybe something for the value of the location tag
  public object Pattern { get; set; }
  public object Continue { get; set; }
}

gc:
  - clean:
      - location: build/buildresults/
        pattern: '*'
      - location: build/testresults/
        pattern: '*'
    dependencies:
      location: blah
  - solution:
      results: build/buildresults/
    test:
      configuration: Release
      results: build/testresults/Release/windows/

1 个答案:

答案 0 :(得分:0)

首先,确保没有任何库已经为您执行此操作(Json 等)。

如果您想自己编程,只要枚举中的所有项目都是 object,这可能适合您:


public static void GetTagsRecursive1(ref List<Tuple<string, string>> addedTags,string keyName, object tagsSource)
        {
            if (addedTags == null)
                addedTags = new List<Tuple<string, string>>();

            if (tagsSource == null)
                return;

            string rootName = keyName != null ? keyName + " >> " : "";

            if (tagsSource is Dictionary<object,object>)
            {      
                foreach (var elem in (tagsSource as Dictionary<object, object>))
                {
                    if (elem.Value is IEnumerable && !(elem.Value is string))
                        GetTagsRecursive(ref addedTags, rootName + elem.Key.ToString(), elem.Value);
                    else
                        addedTags.Add(new Tuple<string, string>(rootName + elem.Key.ToString(), elem.Value.ToString()));
                }
            }
            else if (tagsSource is List<object>)
            {
                foreach (var elem in (tagsSource as List<object>))
                {
                    if (elem is IEnumerable && !(elem is string))
                        GetTagsRecursive(ref addedTags, keyName, elem);
                    else
                        addedTags.Add(new Tuple<string, string>(keyName, elem.ToString()));
                }
            }
            else
                addedTags.Add(new Tuple<string, string>(keyName, tagsSource.ToString()));
        }

并被称为:

   var t = deserializer.ParseYamlTagByType(text);
   List<Tuple<string, string>> addedTags = null;
   GetTagsRecursive(ref addedTags, null, t);

这会给你类似的东西:

  Gc >> clean >> location  >>  build/buildresults/
  Gc >> clean >> pattern  >>  *
  Gc >> clean >> location  >>  build/testresults/
  Gc >> clean >> pattern  >>  *
  Gc >> dependencies >> location  >>  blah
  Gc >> solution >> results  >>  build/buildresults/
  Gc >> test >> configuration  >>  Release
  Gc >> test >> results  >>  build/testresults/Release/windows/

编辑 ---------------------------------

如果不是所有类型都是 object,我想出了一个使用一点反射的解决方案。不过,这可能不是最有效的方法:

    public static void GetTagsRecursive(ref List<Tuple<string, string>> addedTags, string keyName, object tagsSource)
    {
        if (addedTags == null)
            addedTags = new List<Tuple<string, string>>();

        if (tagsSource == null)
            return;

        string rootName = keyName != null ? keyName + " >> " : "";

        if (tagsSource is IEnumerable && !(tagsSource is string))
        {
            IEnumerable myEnumerable = (IEnumerable)tagsSource;

            if (IsDictionary(tagsSource))
            {
                bool PropInfoInit= false;
                System.Reflection.PropertyInfo KeyPropInfo = null, ValuePropInfo = null;
                foreach (var elem in myEnumerable)
                {
                    if (!PropInfoInit)
                    {
                        Type KeyPairType = elem.GetType();
                        KeyPropInfo = KeyPairType.GetProperty("Key");
                        ValuePropInfo = KeyPairType.GetProperty("Value");
                        PropInfoInit= false;
                    }
                    object key = KeyPropInfo.GetValue(elem);
                    object val = ValuePropInfo.GetValue(elem);                           

                    if (val is IEnumerable && !(val is string))
                        GetTagsRecursive(ref addedTags, rootName + key, val);
                    else
                        addedTags.Add(new Tuple<string, string>(rootName + key, val.ToString()));
                }
            }
            else if (IsList(tagsSource))
            {
                foreach (var elem in myEnumerable)
                {
                    if (elem is IEnumerable && !(elem is string))
                        GetTagsRecursive(ref addedTags, keyName, elem);
                    else
                        addedTags.Add(new Tuple<string, string>(keyName, elem.ToString()));
                }
            }
            else
                    throw new Exception("Unexpected Type: " + tagsSource.GetType());                   

        }
        else
            addedTags.Add(new Tuple<string, string>(keyName, tagsSource.ToString()));
}

    static bool IsDictionary(object obj)
    {
        return obj is System.Collections.IDictionary &&
                obj.GetType().IsGenericType &&
                obj.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(Dictionary<,>));
    }

    static bool IsList(object obj)
    {
        return obj is IList &&
                obj.GetType().IsGenericType &&
                obj.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>));
    }

编辑 2 ----------------------------------

基于@theiliii 的评论,假设您想将 yaml 文件转换为非常固定的对象结构,代码可能如下所示:

    public class CalcYamlFile
    {
        const string gcTag = "gc";
        public CalcTag Gc { get; set; } = null;

        public CalcYamlFile(string text)
        {
            var t = deserializer.ParseYamlTagByType(text);

            if (t is Dictionary<object, object>)
            {
                Dictionary<object, object> tdict = t as Dictionary<object, object>;

                object calcTagSource;
                if (tdict.TryGetValue(gcTag, out calcTagSource))
                    Gc = new CalcTag(calcTagSource);
                else
                    Trace.WriteLine("GC tag not found");
            }
        }      
    }

    public class CalcTag
    {
        const string cleanTag = "clean";
        const string dependenciesTag = "dependencies";
        const string solutionTag = "solution";
        const string testTag = "test";
        public Clean Clean { get; set; } = null;
        public Dependencies Dependencies { get; set; } = null;
        public Solution Solution { get; set; } = null;
        public Test Test { get; set; } = null;


        public CalcTag(object tagsSource)
        {
            if (tagsSource != null)
            {
                if (tagsSource is Dictionary<object, object>)
                    AddTagObjects(tagsSource);
                else if (tagsSource is List<object>)
                {
                    foreach (var elem in (tagsSource as List<object>))
                    {
                        if (elem is IEnumerable && !(elem is string))
                            AddTagObjects(elem);
                        else
                            Trace.WriteLine("Unexpected element in CalcTag list");
                    }
                }
            }
        }

        public void AddTagObjects(object tagsSource)
        {
            if (tagsSource != null)
            {
                if (tagsSource is Dictionary<object, object>)
                {
                    foreach (var elem in (tagsSource as Dictionary<object, object>))
                    {
                        switch(elem.Key.ToString())
                        {
                            case cleanTag:
                                if (Clean == null) Clean = new Clean(elem.Value);
                                else Trace.WriteLine($"{cleanTag} Tag already exists");
                                break;
                            case dependenciesTag:
                                if (Dependencies == null) Dependencies = new Dependencies(elem.Value);
                                else Trace.WriteLine($"{dependenciesTag} Tag already exists");
                                break;
                            case solutionTag:
                                if (Solution == null) Solution = new Solution(elem.Value);
                                else Trace.WriteLine($"{solutionTag} Tag already exists");
                                break;
                            case testTag:
                                if (Test == null) Test = new Test(elem.Value);
                                else Trace.WriteLine($"{testTag} Tag already exists");
                                break;
                            default:   Trace.WriteLine($"Unexpected Tag in CalcTag"); break;

                        }
                    }
                }
                else   Trace.WriteLine("Unexpected tagsSource type");
            }
            else Trace.WriteLine("Unexpected null tagsSource");
        }
    }

    public class Clean
    {
        const string patternTag = "pattern";
        const string locationTag = "location";
        public List<Tuple<string, string>> LocationPatternPairs { get; set; } = new List<Tuple<string, string>>();
               
        public Clean(object tagsSource)
        {
            LoadTagsRecursive(tagsSource);
        }
        private void LoadTagsRecursive(object tagsSource)
        {
            if (tagsSource != null)
            {
                if (tagsSource is Dictionary<object, object>)
                {
                    Dictionary<object, object> tagsSouceDict = tagsSource as Dictionary<object, object>;

                    if (tagsSouceDict.ContainsKey(locationTag) && tagsSouceDict.ContainsKey(patternTag))
                    {
                        if (tagsSouceDict.Count > 2)
                            Trace.WriteLine($"Clean source  contains more items than {patternTag} and {locationTag}");

                        LocationPatternPairs.Add(new Tuple<string, string>(tagsSouceDict[locationTag].ToString(), tagsSouceDict[patternTag].ToString()));
                    }
                    else   Trace.WriteLine($"Clean source does not contain {patternTag} or {locationTag}");
                }
                else if (tagsSource is List<object>)
                {
                    foreach (var elem in (tagsSource as List<object>))
                    {
                        if (elem is IEnumerable && !(elem is string))
                            LoadTagsRecursive(elem);
                        else
                            Trace.WriteLine("Unexpected element in Clean list");
                    }
                }
            }   
        }
    }


    public class Dependencies
    {
        const string locationTag = "location";
        public string Location { get; set; }

        public Dependencies(object tagsSource)
        {
            if (tagsSource != null)
            {
                if (tagsSource is Dictionary<object, object>)
                {
                    Dictionary<object, object> tagsSouceDict = tagsSource as Dictionary<object, object>;

                    if (tagsSouceDict.ContainsKey(locationTag))
                    {
                        if (tagsSouceDict.Count > 1)
                            Trace.WriteLine($"Dependencies source  contains more items than {locationTag}");

                        Location = tagsSouceDict[locationTag].ToString();
                    }
                    else Trace.WriteLine($"Dependencies source does not contain {locationTag}");
                }
                else Trace.WriteLine("Unexpected Dependencies source type");
            }
            else Trace.WriteLine("Dependencies source is null");
        }
    }

    public class Solution
    {
        const string resultsTag = "results";
        public object Results { get; set; }

        public Solution(object tagsSource)
        {
            if (tagsSource != null)
            {
                if (tagsSource is Dictionary<object, object>)
                {
                    Dictionary<object, object> tagsSouceDict = tagsSource as Dictionary<object, object>;

                    if (tagsSouceDict.ContainsKey(resultsTag))
                    {
                        if (tagsSouceDict.Count > 1)
                            Trace.WriteLine($"Solution source  contains more items than {resultsTag}");

                        Results = tagsSouceDict[resultsTag].ToString();
                    }
                    else  Trace.WriteLine($"Solution source does not contain {resultsTag}");
                }
                else  Trace.WriteLine("Unexpected Solution source type");
            }
            else Trace.WriteLine("Solution source is null");
        }

    }

    public class Test
    {
        const string ConfigurationTag = "configuration";
        const string resultsTag = "results";
        public string Configuration { get; set; }
        public string Results { get; set; }

        public Test(object tagsSource)
        {
            if (tagsSource != null)
            {
                if (tagsSource is Dictionary<object, object>)
                {
                    Dictionary<object, object> tagsSouceDict = tagsSource as Dictionary<object, object>;

                    if (tagsSouceDict.ContainsKey(resultsTag))      
                        Results = tagsSouceDict[resultsTag].ToString();
                    else Trace.WriteLine($"Test source does not contain {resultsTag}");

                    if (tagsSouceDict.ContainsKey(ConfigurationTag))
                        Configuration = tagsSouceDict[ConfigurationTag].ToString();
                    else Trace.WriteLine($"Test source does not contain {ConfigurationTag}");

                    if (tagsSouceDict.Count > 2)
                        Trace.WriteLine($"Test source  contains more items than {resultsTag} and {ConfigurationTag}");
                }
                else Trace.WriteLine("Unexpected Test source type");
            }
            else Trace.WriteLine("Test source is null");
        }
    }


但请注意,这根本不灵活。只有当您的 yaml 文件中的结构忠实地反映了您的类结构时,它才会起作用,反之亦然