正在从匿名类型获取值

本文关键字:类型 获取 | 更新日期: 2023-09-27 18:27:25

假设我们有以下方法:

public object Test()
{
    return new { A = "Test" };
}

是否有机会获得存储在a中的值?

var b = Test(); //Any chance to cast this to the anonymous type?

正在从匿名类型获取值

注意,从方法返回匿名类型或Tuple<>是一件坏事

但你问了一个关于如何做到这一点的问题,而不是"这是个好主意吗"。。。

通过使用动态或反射。。。

dynamic b = Test();
string str = b.A;

或者通过作弊:

public static object Test()
{
    return new { A = "Test" };
}
public static string GetA(object obj)
{
    // We create an anonymous type of the same type of the one in Test()
    // just to have its type.
    var x = new { A = string.Empty };
    // We pass it to Cast, that will take its T from the type of x
    // and that will return obj casted to the type of the anonymous
    // type
    x = Cast(x, obj);
    // Now in x we have obj, but strongly typed. So x.A is the value we
    // want
    return x.A;
}
public static T Cast<T>(T type, object obj) where T : class
{
    return (T)obj;
}
string str = GetA(Test());

在C#中,同一程序集中具有相同类型的相同属性的所有匿名类型都会合并在一起。因此CCD_ 3的CCD_ 2和CCD_。

Cast<T>是从匿名类型中提取类型的有用技巧。您将键入的匿名类型(该参数仅用于"激活"泛型T)作为第一个参数传递,并将要强制转换的对象作为第二个参数传递。类似的技巧可以用于创建泛型类型的集合,如

public static T MakeList<T>(T type)
{
    return new List<T>();
}

//有没有机会将其转换为匿名类型?

是的,您可以通过示例使用强制转换。

public static T CastByExample<T>(this object obj, T example) {
     return (T)obj;
}

请注意,如果您在同一程序集中,则此有效。如果匿名类型是相同的程序集,则它们具有相同的类型,并且属性具有相同的名称,并且具有相同的顺序。

然后:

object b = Test();
var example = new { A = "example" };
var casted = b.CastByExample(example);
Console.WriteLine(casted.A);

或者,您可以使用dynamic:

dynamic b = Test();
Console.WriteLine(b.A);

或者,使用反射:

object b = Test();
var property = b.GetType().GetProperty("A");
var value = property.GetValue(b);
Console.WriteLine(value);

或者,您可以做正确的事情,创建一个名义(即非匿名)类型

有没有机会将其转换为匿名类型?

虽然你可以这样做,但这是非常不可靠的。因为每当你更改匿名类型的创建时,你的代码就会突然在其他地方中断,没有任何痕迹。

你可以在这里阅读Jon Skeet的博客中关于铸造匿名类型的所有失败之处。同样值得一读的还有MarcGravel的评论。

示例如上面博客中所讨论的,打破变化。

using System;
static class GrottyHacks
{
    internal static T Cast<T>(object target, T example)
    {
        return (T) target;
    }
}
class CheesecakeFactory
{
    static object CreateCheesecake()
    {
        return new { Fruit="Strawberry", Topping="Chocolate" };
    }
    static void Main()
    {
        object weaklyTyped = CreateCheesecake();
        var stronglyTyped = GrottyHacks.Cast(weaklyTyped,
            new { Fruit="", Topping="" });
        Console.WriteLine("Cheesecake: {0} ({1})",
            stronglyTyped.Fruit, stronglyTyped.Topping);            
    }
}

一切都很好。现在,如果你突然意识到你需要将CreateCheeseCake更改为类似的东西,该怎么办

static object CreateCheesecake()
    {
        return new { Fruit="Strawberry", Topping="Chocolate", Base = "Biscuit" };
    }

那么你的这条线会发生什么

var stronglyTyped = GrottyHacks.Cast(weaklyTyped,
            new { Fruit="", Topping="" });

它不会再工作了。