6

私はこの匿名タイプを持っています:

var t= new {a=1,b="lalala",c=DateTime.Now};

どうすればそれを配列にすることができますかObjects(各要素->オブジェクトにキャスト)

したがって、次のようなものになります。

object[]  v = new object[] {1,"lalala",DateTime.Now};

編集

psこれは、あるタイプから別のタイプへの変換を学ぶことについての単なる知識の質問です。オブジェクトの配列を最初から初期化できることはわかっています。しかし、これは学習の質問です。

言及されていないことをお詫びします。

順序は重要です...なぜですか?原因ConstructorInfo.Invoke は受け入れています

タイプ:System.Object []この...のパラメーターの数、順序(!!!)、およびタイプ(デフォルトのバインダーの制約下)に一致する値の配列。

4

6 に答える 6

6

基本的にはリフレクションを使用する必要があります。経由でそれほど難しいことではないはずType.GetPropertiesですが、「組み込み」については何も知りません。

leppieが指摘したように、順序付けは単純ではありません。パラメーターの順序を調べる必要があります。これにより、少なくともすべてのタイプのプロパティの順序がわかります。異なるタイプしかない場合は、それで問題ありません。

順序を気にしない場合は、次を使用できます。

var array = t.GetType()
             .GetProperties()
             .Select(p => p.GetValue(t, null))
             .ToArray();

編集:私は実際にそれを修正する何かを考えましたが、それは実装固有です。C#コンパイラは、ジェネリック型を使用して匿名型を生成します。したがってnew { A = 5, B = "foo" }、実際には次のような匿名タイプを作成します。

class <>_Anon<TA, TB>
{
    internal <>_Anon(TA a, TB b)
}

したがって、ジェネリックプロパティのジェネリックタイプに基づいてプロパティ名を順番に計算してから、具象タイプから順番にプロパティをフェッチできます。しかし、それは醜いです...

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"
        }
    }
}
于 2012-06-26T17:10:05.450 に答える
4
public object[] ToPropertyArray(object o)
{
    return o.GetType.GetProperties()
        .Select(p => p.GetValue(o, null))
        .ToArray();
}

編集:匿名型からある型のコンストラクターを呼び出したいようです。これが可能な唯一の方法は、パラメータ名が匿名タイプのプロパティ名と一致する場合のようです。

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));
}
于 2012-06-26T17:12:20.320 に答える
1

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

GetValueコンソールにプロパティ名を書き込む代わりに、を使用して配列に追加できるはずです。

于 2012-06-26T17:11:32.147 に答える
0

匿名型がコンパイル時に既知の同じプロパティを常に持つ場合は、明白な明示的なアプローチを使用できます。

var t = new { a = 1, b = "lalala", c = DateTime.Now };
object[] v = new object[] { t.a, t.b, t.c };
于 2012-06-26T17:14:00.867 に答える
0

リフレクションは、動的に作成する必要がある場合に使用する方法です。動的である必要がない場合は、明らかにこのようにすることができますが、すでにこれについて考えていると思います。

var t = new { a = 1, b = "lalala", c = DateTime.Now };

object[] v = new object[] { t.a, t.b, t.c };

あなたは私たちに先に進むことをあまり与えていないので、あなたの問題についてより深い視点を提供できますか?おそらく、あなたがアノンタイプから始めなければ、より良い解決策がありますか?

于 2012-06-26T17:17:07.793 に答える
0

ToStringこれは、匿名型がどのように生成されるかについての微妙な詳細ではなく、結果に依存しているため、JonSkeetのソリューションよりも優れていると思います。

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();

匿名型のオブジェクトがレンダリングされる可能性から保護する必要がある場合は、myAnonToStringメソッドコード( )から文字列定数を読み取ることもできる場合があります。これにより、単純なパーサーが破棄されます。myAnon.GetType().GetMethod("ToString").GetMethodBody()" = "

于 2012-06-26T17:43:38.377 に答える