Reputation: 148524
I have this anonymous type :
var t= new {a=1,b="lalala",c=DateTime.Now};
How can I make it an array of Objects
( each element -> cast to object)
hence to something like :
object[] v = new object[] {1,"lalala",DateTime.Now};
p.s. this is just a knowledge question about learning to convert from 1 type to other. i know i can initialize an array of object from the beginning. but this is a learning question.
sorry for not mentioned it.
order Is important...why? cause ConstructorInfo.Invoke is accepting
Type: System.Object[] An array of values that matches the number, order (!!!) and type (under the constraints of the default binder) of the parameters for this ....
Upvotes: 6
Views: 8086
Reputation: 56536
I think this is better than Jon Skeet's solution, since it relies on the result of ToString
rather than on subtler details of how anonymous types are generated:
var myAnon = new { a = "hi", b185310 = "lo" };
var names = Regex.Matches(myAnon.ToString(), @"([a-zA-Z0-9]+) = ");
var objArray = names.Cast<Match>().Select(name => myAnon.GetType().GetProperty(name.Groups[1].ToString()).GetValue(myAnon, null)).ToArray();
You might also be able to read the string constants from myAnon
's ToString
method code (myAnon.GetType().GetMethod("ToString").GetMethodBody()
) if you need to protect against the possibility of an object in the anonymous type being rendered with " = "
in it, thus throwing off the simplistic parser.
Upvotes: 0
Reputation: 144136
public object[] ToPropertyArray(object o)
{
return o.GetType.GetProperties()
.Select(p => p.GetValue(o, null))
.ToArray();
}
EDIT: It looks like you want to invoke a constructor of some type from an anonymous type. It looks like the only way this is possible is if the parameter names match the property names of the anonymous type:
public static T ConstructFromAnonymous<T>(object anon)
{
//get constructors for type ordered by number of parameters
var constructors = typeof(T).GetConstructors().OrderByDescending(c => c.GetParameters().Length);
//get properties from anonymous object
Dictionary<string, PropertyInfo> properties = anon.GetType()
.GetProperties()
.ToDictionary(p => p.Name);
ConstructorInfo bestMatch = constructors.FirstOrDefault(ci => IsMatch(ci, properties));
if (bestMatch != null)
{
var parameters = bestMatch.GetParameters();
object[] args = parameters.Select(p => properties[p.Name].GetValue(anon, null)).ToArray();
return (T)bestMatch.Invoke(args);
}
else throw new ArgumentException("Cannot construct type");
}
private static bool IsMatch(ConstructorInfo ci, Dictionary<string, PropertyInfo> properties)
{
var parameters = ci.GetParameters();
return parameters.All(p => properties.ContainsKey(p.Name) && p.ParameterType.IsAssignableFrom(properties[p.Name].PropertyType));
}
Upvotes: 4
Reputation: 1500425
You'd have to use reflection, basically. It shouldn't be too hard via Type.GetProperties
, but I don't know of anything "built-in".
As leppie pointed out, the ordering isn't simple - you'd have to examine the order of the parameters, which would at least give you the order of all the types of the properties. If you only had different types, that would be fine.
If you don't care about the ordering, you can use:
var array = t.GetType()
.GetProperties()
.Select(p => p.GetValue(t, null))
.ToArray();
EDIT: I've just thought of something which will actually fix it, but it's implementation specific. The C# compiler generates anonymous types using generic types. So new { A = 5, B = "foo" }
will actually create an anonymous type like this:
class <>_Anon<TA, TB>
{
internal <>_Anon(TA a, TB b)
}
so you can work out the property names in order based on the generic types of the generic properties, then fetch the properties in order from the concrete type. But it's ugly...
using System;
using System.Linq;
using System.Reflection;
class Test
{
// Note: this uses implementation details of anonymous
// types, and is basically horrible.
static object[] ConvertAnonymousType(object value)
{
// TODO: Validation that it's really an anonymous type
Type type = value.GetType();
var genericType = type.GetGenericTypeDefinition();
var parameterTypes = genericType.GetConstructors()[0]
.GetParameters()
.Select(p => p.ParameterType)
.ToList();
var propertyNames = genericType.GetProperties()
.OrderBy(p => parameterTypes.IndexOf(p.PropertyType))
.Select(p => p.Name);
return propertyNames.Select(name => type.GetProperty(name)
.GetValue(value, null))
.ToArray();
}
static void Main()
{
var value = new { A = "a", Z = 10, C = "c" };
var array = ConvertAnonymousType(value);
foreach (var item in array)
{
Console.WriteLine(item); // "a", 10, "c"
}
}
}
Upvotes: 6
Reputation: 1230
Reflection is the way to go if you need it dynamically created. If it doesn't need to be dynamic you could obviously do it like this but I assume you've already thought of this:
var t = new { a = 1, b = "lalala", c = DateTime.Now };
object[] v = new object[] { t.a, t.b, t.c };
Could you provide a more in-depth perspective on your issue as you're not giving us much to go on, perhaps there is a better solution if you don't begin with an anon type?
Upvotes: 0
Reputation: 54877
If your anonymous type will always have the same properties which are known at compile-time, then you could use the obvious explicit approach:
var t = new { a = 1, b = "lalala", c = DateTime.Now };
object[] v = new object[] { t.a, t.b, t.c };
Upvotes: 0
Reputation: 28752
static void Main()
{
//Anonymous Type
var anyType = new
{
IntID = 1,
StringName = "Wriju"
};
Type t = anyType.GetType();
PropertyInfo[] pi = t.GetProperties();
foreach (PropertyInfo p in pi)
{
//Get the name of the prperty
Console.WriteLine(p.Name);
}
//Using LINQ get all the details of Property
var query = from p in t.GetProperties()
select p;
ObjectDumper.Write(query);
}
You should be able to add to array using GetValue
instead of writing property name to console.
Upvotes: 1