【问题标题】:How can I convert a class into Dictionary<string,string>?如何将类转换为 Dictionary<string,string>?
【发布时间】:2012-03-01 21:33:11
【问题描述】:

我可以将 Class 转换为 Dictionary 吗?

在字典中,我希望我的类属性为 keys,特定属性的值作为 value

假设我的班级是

public class Location
{
    public string city { get; set; }
    public string state { get; set; }
    public string country { get; set;
}

现在假设我的数据是

city = Delhi
state = Delhi
country = India

现在你可以轻松理解我的意思了!

我想做一本字典!那个字典应该是这样的:

Dictionary<string,string> dix = new Dictionary<string,string> ();
dix.add("property_name", "property_value");

我可以得到价值!但是如何获取属性名称(不是值)?

我应该编写什么代码来动态创建它?这应该适用于我想要的每一门课。

你可以把这个问题理解为:

如何获取特定类的属性列表?

现在我再次解释我对字典的渴望之一!这个问题从我的previous question@ 的回答中突然出现在我的脑海中!!

【问题讨论】:

  • 你能试着改写这个问题吗?我不知道你想要达到什么目的。
  • 调查!我想要特定类的所有变量的名称!这可能吗?
  • @NoOne 我已经回答了你,但你需要了解更多关于 OOP 的知识。你说的是属性。而类级别的“变量”被称为fields。用它的名字来称呼一切很重要,因为你比现在更容易理解! ;)
  • @MatíasFidemraizer 对不起!我的错误我应该使用我编辑过的“属性”!
  • @Chintan 我不知道你打算在哪里使用类字典,请注意,与你的类相反,“国家”可以是 Country 类型的属性,而城市是类型string,您必须在字典中指定要存储的最基本类型(很可能是object),这将使您的生活更加艰难。

标签: c# asp.net dictionary


【解决方案1】:

这就是秘诀:1 个反射,1 个 LINQ-to-Objects!

 someObject.GetType()
     .GetProperties(BindingFlags.Instance | BindingFlags.Public)
          .ToDictionary(prop => prop.Name, prop => (string)prop.GetValue(someObject, null))

自从我发布这个答案以来,我已经检查了很多人发现它很有用。我邀请所有寻找这个简单解决方案的人检查另一个问答,我将其概括为扩展方法:Mapping object to dictionary and vice versa

【讨论】:

  • 如果我看到像“GenericEqualityComparer”这样的“内在”属性,而不是我明确声明的属性怎么办?我试过BindingFlags.DeclaredOnly
  • UPDATE 没关系 - 我发现使用此反射的方法(本身在对象扩展中)最终使用转换后的结果调用自身,因此我的扩展被调用对象 AND THEN 在结果字典上。
  • 当我尝试这个时它返回 Dictionary 而不是 Dictionary,因此不满足 OP。
  • @TimWilliams 谢谢,我已经解决了这个问题 ;-)
  • @TimWilliams 你错过了演员阵容吗?
【解决方案2】:

这里是一个没有LINQ的反射示例:

    Location local = new Location();
    local.city = "Lisbon";
    local.country = "Portugal";
    local.state = "None";

    PropertyInfo[] infos = local.GetType().GetProperties();

    Dictionary<string,string> dix = new Dictionary<string,string> ();

    foreach (PropertyInfo info in infos)
    {
        dix.Add(info.Name, info.GetValue(local, null).ToString());
    }

    foreach (string key in dix.Keys)
    {
        Console.WriteLine("nameProperty: {0}; value: {1}", key, dix[key]);
    }

    Console.Read();

【讨论】:

  • 这为我节省了至少一天的工作时间。非常感谢,如果可以的话,我会投票给你两次!
【解决方案3】:
protected string getExamTimeBlock(object dataItem)
{
    var dt = ((System.Collections.Specialized.StringDictionary)(dataItem));

    if (SPContext.Current.Web.CurrencyLocaleID == 1033) return dt["en"];
    else return dt["sv"];
}

【讨论】:

  • 解释一下。
【解决方案4】:

试试这个。

这使用反射来检索对象类型,然后是所提供对象的所有属性(PropertyInfo prop in obj.GetType().GetProperties(),请参阅https://docs.microsoft.com/en-us/dotnet/api/system.type.getproperties?view=netcore-3.1)。然后它将属性名称作为键添加到字典中,如果存在值,则添加该值,否则添加 null。

    public static Dictionary<string, object> ObjectToDictionary(object obj)
    {
        Dictionary<string, object> ret = new Dictionary<string, object>();

        foreach (PropertyInfo prop in obj.GetType().GetProperties())
        {
            string propName = prop.Name;
            var val = obj.GetType().GetProperty(propName).GetValue(obj, null);
            if (val != null)
            {
                ret.Add(propName, val);
            }
            else
            {
                ret.Add(propName, null);
            }
        }

        return ret;
    }

【讨论】:

  • 解释一下。
  • 会修改答案。
【解决方案5】:

我想使用 JToken 添加反射的替代方法。您需要检查两者之间的基准差异,看看哪个具有更好的性能。

var location = new Location() { City = "London" };
var locationToken = JToken.FromObject(location);
var locationObject = locationObject.Value<JObject>();
var locationPropertyList = locationObject.Properties()
    .Select(x => new KeyValuePair<string, string>(x.Name, x.Value.ToString()));

请注意,此方法最适合扁平类结构。

【讨论】:

  • var locationObject = locationObject.Value&lt;JObject&gt;();?
  • 这是一个更紧凑的版本:var props = JToken.FromObject(query) .Value&lt;JObject&gt;() .Properties() .ToDictionary(k =&gt; k.Name, v =&gt; $"{v.Value}");
【解决方案6】:

只是送给某人的礼物只需要一个简单而扁平的Dictionary&lt;String,String&gt; 不需要层次结构或反序列化回像我这样的对象?

    private static readonly IDictionary<string, string> SPECIAL_FILTER_DICT = new Dictionary<string, string>
    {
        { nameof(YourEntityClass.ComplexAndCostProperty), "Some display text instead"},
        { nameof(YourEntityClass.Base64Image), ""},
        //...
    };


    public static IDictionary<string, string> AsDictionary(this object source, BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)
    {
        if (source == null)
            return new Dictionary<string, string> {
                {"",""}
            };

        return source.GetType().GetProperties(bindingAttr).ToDictionary
        (
            propInfo => propInfo.Name,
            propInfo => propInfo.GetValue(source, null).GetSafeStringValue(propInfo.Name)
        );
    }


    public static String GetSafeStringValue(this object obj, String fieldName)
    {
        if (obj == null)
            return "";

        if (obj is DateTime)
            return GetStringValue((DateTime)obj);

        // More specical convert...

        if (SPECIAL_FILTER_DICT.ContainsKey(fieldName))
            return SPECIAL_FILTER_DICT[fieldName];

        // Override ToString() method if needs
        return obj.ToString();
    }


    private static String GetStringValue(DateTime dateTime)
    {
        return dateTime.ToString("YOUR DATETIME FORMAT");
    }

【讨论】:

    【解决方案7】:

    我希望这个扩展对某人有用。

    public static class Ext {
        public static Dictionary<string, object> ToDict<T>(this T target)
            => target is null
                ? new Dictionary<string, object>()
                : typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
                            .ToDictionary(
                                x => x.Name,
                                x => x.GetValue(target)
                            );
    }
    

    【讨论】:

    • 它有效,但我认为这是否是一种抽象逻辑的扩展方法,它的语法被过度压缩并被语言“糖”所掩盖。在这种情况下,我会将逻辑保留为更冗长的格式,因为它更容易阅读。
    • 解释一下。
    【解决方案8】:
    public static Dictionary<string, object> ToDictionary(object model)
        {
            var serializedModel = JsonModelSerializer.Serialize(model);
            return JsonModelSerializer.Deserialize<Dictionary<string, object>>(serializedModel);
        }
    

    我已经使用了上面的代码。尽可能简化,它可以在没有反射的情况下工作,模型可以嵌套并且仍然可以工作。 (如果您使用 Json.net,请将您的代码更改为不使用 Newtonsoft)

    【讨论】:

    • 我认为这种方法的效率要低得多(而且我确信 JsonModelSerializer 在内部使用反射......所以如果没有反射,它就无法真正工作。)
    猜你喜欢
    • 1970-01-01
    • 2014-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    相关资源
    最近更新 更多