如何返回一个Dictionary<int, object>?

5

这个有效:

public IDictionary<int, object> GetProducts( int departmentID )
{
    return new Dictionary<int, object>
                {
                    { 1, new { Description = "Something" } },
                    { 2, new { Description = "Whatever" } },
                };
}

但由于某些原因,这并不起作用:
public IDictionary<int, object> GetProducts( int departmentID )
{
    var products = ProductRepository.FindAll( p => p.Department.Id == departmentID );

    return products.ToDictionary( p => p.Id, p => new { Description = p.Description } );
}

这也不起作用:
public IDictionary<int, object> GetProducts( int departmentID )
{
    var products = ProductRepository.FindAll( p => p.Department.Id == departmentID );

    return products.ToDictionary( p => p.Id, p => new { p.Description } );
}

编译器错误(两种情况下都是):
Cannot convert expression type 'System.Collections.Generic.Dictionary<int,{Description:string}>' to return type 'System.Collections.Generic.IDictionary<int,object>'

我认为这是ToDictionary Linq扩展方法的问题,但根据这个答案,它应该可以工作,因为FindAll返回一个IQueryable<Product>

... if your data is coming from an IEnumerable or IQueryable source, you can get one using the LINQ ToDictionary operator and projecting out the required key and (anonymously typed) value from the sequence elements:

var intToAnon = sourceSequence.ToDictionary(
    e => e.Id,
    e => new { e.Column, e.Localized });

发生了什么事?


2
请注意,你必须将值转换为除 object 以外的其他类型才能对其进行任何有用的操作。由于实际值是匿名类型,因此你需要使用反射或 dynamic,但它们都不是编译时安全的。最好创建一个具体的类,并将其用作结果值类型。 - D Stanley
返回值被序列化为JSON,这非常有用。仅为序列化JSON而创建模型对我来说似乎是多余的。 - Big McLargeHuge
真的 - 这是一个有效的用法。 - D Stanley
2个回答

8

将字典值明确转换为object会怎样呢?

return products.ToDictionary( p => p.Id, p => (object)new { Description = p.Description } )

实际上,匿名对象是编译时随机创建的常规类的实例,因此它是一个对象,但它是某种特定类型的对象。这就是为什么你不能期望隐式地强制转换为IDictionary<string, object>的原因。
也许如果IDictionary<TKey, TValue>支持协变TValue...

你能澄清一下你协变的评论吗?我不确定那会如何解决问题。 - Big McLargeHuge
@DStanley 这就是为什么我说“如果它会...”,我还没有参与讨论它是否可能或不可能... - Matías Fidemraizer
@DStanley 我重新表达了最后一句话 :D - Matías Fidemraizer

6

使用匿名类型进行工作是不良的做法,就像你所做的那样。不要尝试将它们包装成object。如果您需要使用匿名类型,请在定义它们的同一方法上下文中使用。

只需更改您的方法如何?

public IDictionary<int, object> GetProducts( int departmentID )
{
    return new Dictionary<int, object>
                {
                    { 1, "Something"},
                    { 2, "Whatever"},
                };
}

然后将对象转换回字符串?

当然,这是在假设您无法只更改类型为 IDictionary<int, string> 的情况下。


该值实际上需要多个属性(不仅仅是描述),例如价格、名称、颜色等。我在示例中只包含了一个属性,以使其简单化。为什么这是不好的做法? - Big McLargeHuge
1
@Koveras 因为你无法将对象强制转换回匿名类型。你将被迫使用 dynamic 或反射来获取属性。通常最好创建类来存储您的值。 - juharr
@Koveras 在你的情况下,创建一个额外的产品类来保存数据也是合理的。 - CodeMonkey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接