6

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};

edit

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 ....

5
  • 3
    Fields dont have implicit order, so how will this work? Commented Jun 26, 2012 at 17:10
  • Perhaps you should use a named type in this case. Commented Jun 26, 2012 at 17:11
  • You don't. There is a difference between a Type which has members, and an array. That's like saying: How do I take a System.Windows.Forms.Form and convert all it's members into an object[]. That's not to say it's not doable, it's to say it's not a proper analogy. Commented Jun 26, 2012 at 17:11
  • What are you really trying to do here? Are you trying to match a constructor to an anonymous type? How will you disambiguate properties if there are multiple arguments with the same type? Commented Jun 26, 2012 at 17:19
  • @Lee as my edit says , just learning. Commented Jun 26, 2012 at 17:20

6 Answers 6

6

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"
        }
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

hi ive edited. order is important. sorry for not mentioned it.
i know :).... just wanted to see if i could convert it myself... and nope... didnt succeed.. its just a teasing question. ( for learning ofcourse)
@RoyiNamir: I've included the code now. It's really nasty... and definitely implementation-specific. But it should work for the MS compiler :)
:) thanks. now im smarter (c-sharply)than i was before 5 min.
4
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));
}

Comments

1

See http://blogs.msdn.com/b/wriju/archive/2007/10/26/c-3-0-anonymous-type-and-net-reflection-hand-in-hand.aspx:

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.

Comments

0

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 };

Comments

0

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?

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.