C# 以对象为值的字典

C# 以对象为值的字典,c#,object,dictionary,C#,Object,Dictionary,我快发疯了。这可能是因为我错过了一些规则,但如果是这样,请告诉我 我正在尝试创建一个字典,其中一个字符串作为键,一个匿名对象作为值。或者,事实上我不只是在尝试,我在做。 但是当我想要改变对象中的一个特定参数时,它会出错 我这样声明字典: var areas = new Dictionary<string, object> { {"Key1", new {name = "Name1", today = 0, all = 0}}, {"Key2", new {name = "Na

我快发疯了。这可能是因为我错过了一些规则,但如果是这样,请告诉我

我正在尝试创建一个
字典
,其中一个字符串作为键,一个匿名对象作为值。或者,事实上我不只是在尝试,我在做。 但是当我想要改变对象中的一个特定参数时,它会出错

我这样声明字典:

var areas = new Dictionary<string, object>
{
  {"Key1", new {name = "Name1", today = 0, all = 0}},
  {"Key2", new {name = "Name2", today = 0, all = 0}},
    ...
}
但VisualStudio不同意,并拒绝编译。不过,如果我写这篇文章,一切都会按照我的想法进行——但这并没有真正帮助我,只是让我更加沮丧

var areaname = new 
            {
                 name = "Nametest", today = 0, all = 0
            };
var testname = areaname.name;
我做错了什么?为什么它对我不起作用?难道这根本不可能吗

谢谢你的回答,他们肯定把事情弄清楚了一点!
我想我可能在C#中出于沮丧而混淆了类型对象和对象的概念,即类。我将重新思考整个设计业务,可能会做一些完全不同的事情,而不是使用邪恶或肮脏的解决方案。虽然很有趣,但我认为我与C#的关系还没有发展到那个程度

这将不起作用,因为您已将字典声明为
字典


您可以尝试使用
字典

,因为字典中的值属于
对象
类型,并且
对象
不包含属性
名称

如果您使用的是.NET 4,则可以将类型从
对象
更改为
动态


话虽如此,我强烈反对这一设计决定。你真的应该为此创建一个类。

匿名类型的详细信息在创建它们的程序集之外是不可移植的,在创建它们的方法之外也不容易看到。您应该使用onymous类型,或者如果您想采用动态方法,则应使用
dynamic


†这里有一个邪恶的把戏,我故意不提,因为它是邪恶的。

这不起作用,因为您已将字典声明为
字典

C#在后台为您创建一个新类型(您无法访问),该类型具有这些属性(以下称为匿名类型)。唯一可以直接使用它的时候是当它仍然是
var
类型时-一旦你将它添加到字典中,它就会被转换为
对象
,因此你不能再访问属性了

选项1

您可以尝试使用
字典
。Dynamic将能够访问这些属性,但这仅在C#/.Net 4.0中受支持

选项2

您可以使用一种称为“演示”的技术(通过示例转换)将类型恢复。这不是一个记录在案的功能,是浪费,是有点黑客。-特别是因为它不能跨程序集工作

public static T Demonstrate<T>(this T demonstration, object value)
{
    return (T)value;
}
选项3老实说,这是最好的方法

写一节课。如果您喜欢C#编译器执行所有的
Equals
GetHashCode
ToString
操作,那么您可以使用类似的方法获取原始代码。因此:

class AreaInfo
{
    public string Name { get; set; }
    public int Total { get; set; }
    public int All { get; set; }

    public override bool Equals(object obj)
    {
        var ai = obj as AreaInfo;
        if (object.ReferenceEquals(ai, null))
            return false;
        return Name == ai.Name && Total == ai.Total && All == ai.All;
    }

    public override int GetHashCode()
    {
        var hc = 0;
        if (Name != null)
            hc = Name.GetHashCode();
        hc = unchecked((hc * 7) ^ Total);
        hc = unchecked((hc * 21) ^ All);
        return hc;
    }

    public override string ToString()
    {
        return string.Format("{{ Name = {0}, Total = {1}, All = {2} }}", Name, Total, All);
    }
}
更正您的字典:

var areas = new Dictionary<string, AreaInfo>       
{       
  {"Key1", new AreaInfo() {Name = "Name1", Today = 0, All = 0}},       
  {"Key2", new AreaInfo() {Name = "Name2", Today = 0, All = 0}},       
    ...       
};
var区域=新字典
{       
{“Key1”,newAreaInfo(){Name=“Name1”,今天=0,所有=0},
{“Key2”,newAreaInfo(){Name=“Name2”,今天=0,所有=0},
...       
};

现在,事情将按您期望的方式进行。

要使您的词典的值具有适当的匿名类型,请执行以下操作:

var areas=new[] {
  new {Key="Key1", Value=new {name="Name1", today=0, all=0}},
  new {Key="Key2", Value=new {name="Name2", today=0, all=0}},
}.ToDictionary(kv => kv.Key, kv => kv.Value);
然后,您的代码将按预期工作:

foreach(var area in areas.Keys.ToArray()) {
  var areaname=areas[area].name;
}

是否尝试使用“动态”而不是“对象”作为值类型?编译器无法解析从字典中检索的对象(值)的Name属性。对于var的情况,编译器会将real-on-the-fly类型替换为var,以辅助编译器。在这种情况下,为什么需要匿名类型?当您知道所有值上应该存在哪些属性时,即它不是未知的。您的“演示”方法(通常也称为“CastByExample”)并不可怕,因为它可能会在该语言的未来版本中中断;这是一部完美的法律法规,没有任何实施定义的行为。这应该永远有效。但是,这很可怕,因为它不能跨程序集工作。如果您有一个由程序集ABC.dll创建的匿名类型字典,并且程序集XYZ.dll尝试通过示例强制转换,则即使匿名类型具有相同的“形状”,转换也将失败。匿名类型仅在创建它们的程序集中相同。@Eric-我知道你为MSFT工作:),但它不属于未记录行为的范畴吗?@Jonathan我去检查了-C#3.0规范,7.5.10.6:在同一程序中,两个匿名对象初始值设定项以相同顺序指定相同名称和编译时类型的属性序列,将生成相同匿名类型的实例。“您忘记了如何包含从字典中提取AreaInfo的代码了。在定义它们的整个程序集中,匿名类型实际上被记录为在结构上是等效的,而不仅仅是在一个方法中。此外,尽管“匿名类型”很可爱,“命名类型”更好。我有时使用“名义类型”“,虽然这有“仅名称中的类型”而不是“具有特定名称的类型”的不幸贬义。@nawfal-我同意这是最接近OP问题的答案,但是我不确定为了代码的可读性,创建一个实际的类是否更好(尽管我通常会尽量避免创建一个仅用作“临时”数据容器的类)@BornToCode是的。你是对的。在这里使用实际命名类型可能是最好的选择。我应该说这是这里最酷的解决方案(因为OP严格要求匿名类型):)
var areas=new[] {
  new {Key="Key1", Value=new {name="Name1", today=0, all=0}},
  new {Key="Key2", Value=new {name="Name2", today=0, all=0}},
}.ToDictionary(kv => kv.Key, kv => kv.Value);
foreach(var area in areas.Keys.ToArray()) {
  var areaname=areas[area].name;
}