A dictionary where value is an anonymous type in C#
Is it possible in C# to create a System.Collections.Generic.Dictionary<TKey, TValue>
where TKey
is unconditioned class and TValue
- an anonymous class with a number of properties, for example - database column name and it's localized name.
Something like this:
new { ID = 1, Name = new { Column = "Dollar", Locali开发者_JS百科zed = "Доллар" } }
You can't declare such a dictionary type directly (there are kludges but these are for entertainment and novelty purposes only), but 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 });
As itowlson said, you can't declare such a beast, but you can indeed create one:
static IDictionary<TKey, TValue> NewDictionary<TKey, TValue>(TKey key, TValue value)
{
return new Dictionary<TKey, TValue>();
}
static void Main(string[] args)
{
var dict = NewDictionary(new {ID = 1}, new { Column = "Dollar", Localized = "Доллар" });
}
It's not clear why you'd actually want to use code like this.
You can do a refection
public static class ObjectExtensions
{
/// <summary>
/// Turn anonymous object to dictionary
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static IDictionary<string, object> ToDictionary(this object data)
{
var attr = BindingFlags.Public | BindingFlags.Instance;
var dict = new Dictionary<string, object>();
foreach (var property in data.GetType().GetProperties(attr))
{
if (property.CanRead)
{
dict.Add(property.Name, property.GetValue(data, null));
}
}
return dict;
}
}
I think ASP.NET MVC didn't exit at the time this question was made. It does convert anonymous objects to dictionaries internally.
Just take a look at the HtmlHelper
class, for example. The method that translates objects to dictionaries is the AnonymousObjectToHtmlAttributes
. It it's specifc to MVC and returns an RouteValueDictionary
, however.
If you want something more generic, try this:
public static IDictionary<string,object> AnonymousObjectToDictionary(object obj)
{
return TypeDescriptor.GetProperties(obj)
.OfType<PropertyDescriptor>()
.ToDictionary(
prop => prop.Name,
prop => prop.GetValue(obj)
);
}
One intersting advantages of this implementation is that it returns an empty dictionary for null
objects.
And here's one generic version:
public static IDictionary<string,T> AnonymousObjectToDictionary<T>(
object obj, Func<object,T> valueSelect
)
{
return TypeDescriptor.GetProperties(obj)
.OfType<PropertyDescriptor>()
.ToDictionary<PropertyDescriptor,string,T>(
prop => prop.Name,
prop => valueSelect(prop.GetValue(obj))
);
}
If you would like to initialize an empty dictionary you could do something like the this:
var emptyDict = Enumerable
.Empty<(int, string)>()
.ToDictionary(
x => new { Id = x.Item1 },
x => new { Column = x.Item2, Localized = x.Item2});
Basically you just need an empty enumerable with a tuple that has the types you want to use in your final anonymous types and then you can get an empty dictionary that is typed the way you'd like.
If you wanted to you could name the types in the tuple as well:
var emptyDict = Enumerable
.Empty<(int anInt, string aString)>()
.ToDictionary(
x => new { Id = x.anInt },
x => new { Column = x.aString, Localized = x.aString});
精彩评论