c# - 遍历字典值
问题描述
嘿,我正在反序列化一个 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/
解决方案
首先,确保没有任何库可以为您执行此操作(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 文件中的结构忠实反映您的类结构时,它才会起作用,反之亦然
推荐阅读
- c++ - 对 RIPEMD160 消息摘要执行 SHA256 哈希
- firebase - 如何将 TS 路径映射与 Firebase 云函数一起使用
- c++ - C++ 如何理解这两种输入模式?
- twitter-bootstrap-3 - 下拉菜单中下拉切换类的用途是什么
- sony-audio-control-api - 索尼 ZR5 音频控制 API
- node.js - Mongo 在每次页面刷新时建立新连接
- bittorrent - uTorrent 的 uTorrentPartFile.dat 的结构
- excel - 如果每个值的总和满足特定标准,则总和分配的值
- math - 查找拍摄照片球的位置
- javascript - 以下带有生成器的代码块 BrowserSync