【问题标题】:C# runtime introspection on Tuple元组上的 C# 运行时自省
【发布时间】:2017-11-22 15:52:38
【问题描述】:

在我的 C# 应用程序中,我需要向用户显示一个元组。问题是元组可以是任何形式,我不知道在编译时元组会是什么样子,所以我必须在运行时对其进行反省才能显示它。第一个问题是识别元组中每个组件的类型,第二个是获取每个组件的值。

获取每个组件的值好像涉及到Item1、Item2等等,但是有没有办法通过索引来获取Items呢?目前我的代码真的很笨重,因为我必须使用组件的数量来决定如何迭代项目(见下文)。然而,更大的问题是如何获取元素,因为我不知道如何获取 Tuple 对象。以下代码可以编译,但在运行时将对象转换为 Tuple 会引发这种形式的错误:

无法转换类型为“System.Tuple2[System.String,System.Byte[]]' to type 'System.Tuple2[System.Object,System.Object]”的对象。

看起来演员表失败了(我想我明白为什么),但我不知道如何重写演员表来解决这个问题。我试过这样的事情:

object rowObject = ((Tuple<tupleTypeArray[0], tupleTypeArray[1]>)tupleObject ).Item1;

但这不会编译。帮助将不胜感激!

tupleObject = SomeTupleGotFromMethodCall();
Type tupleType = tupleObject.GetType();
Type[] tupleTypeArray = tupleType.GenericTypeArguments;
int tupleLength = tupleType.GenericTypeArguments.Count<Type>();
for (int i = 0; i < tupleLength; i++)
{
    if (tupleLength == 1)
    {
        if (i == 0)
        {
            Type firstType = tupleTypeArray[0];
            object rowObject = ((Tuple<object>)tupleObject).Item1;
            if (rowObject != null)
            {
                display(rowObject);
            }
        }
    }

    if (tupleLength == 2)
    {
        if (i == 0)
        {
            object rowObject = ((Tuple<object, object>)tupleObject).Item1;
            if (rowObject != null)
            {
                display(rowObject);
            }
        }

        if (i == 1)
        {
            object rowObject = ((Tuple<object, object>)tupleObject).Item2;
            display(rowObject);
        }
    }

    ...
}

【问题讨论】:

  • 使用元组作为列表从来都不是一个好主意,你有实现返回元组的方法吗?
  • 不 - 我无法控制返回的内容 - 这是一个单独的库。在执行上述代码之前,元组并不是唯一可以返回的对象类型(我会处理这些其他类型)。
  • 我首先要说 'object' 是一种类型,所以你的前两行没有意义(然后是 avery cast)
  • 是的,抱歉 - 为了便于阅读,我编辑了代码,但使用了错误的变量名!我已更新问题以更正该问题。
  • 你不能使用类似 var item1 = tupleObject.GetType().GetProperty("Item1").GetValue(tupleobject, null);等等?

标签: c# reflection tuples


【解决方案1】:

这不行:

object rowObject = ((Tuple<object>)tupleObject).Item1;

因为Tuple&lt;int&gt; 不是 Tuple&lt;object&gt;。仅仅因为int 继承自object 并不意味着Tuple&lt;int&gt; 继承自Tuple&lt;object&gt;

您真正想要做的是获取未知类型对象的所有属性,并显示它们。这不是一个元组问题,尤其是。使用元组执行此操作与使用任何其他对象执行此操作没有什么不同。属性就是属性。除非它们是字段;那么它们根本就不是属性。但是对于元组,它们是属性。

所以我们只需要编写一个快速扩展方法,它会返回任何给定对象的公共属性的所有名称和值——我们也会输入属性的类型,因为我们还不如完整.

获得属性的名称和值后,您可以编写代码以任何您喜欢的方式显示它们。

public static class Extensions
{
    //  nuget Install-Package "System.ValueTuple" if the compiler gives you any backtalk
    public static List<(String Name, Type Type, Object Value)> 
        GetPublicPropertiesWithValues(this object obj)
    {
        return 
            obj.GetType()
            .GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .Select(p => (
                Name: p.Name, 
                Type: p.PropertyType, 
                Value: p.GetValue(obj)
            ))
            .ToList();
    }
}

演示:

class Program
{
    static void Main(string[] args)
    {
        var tuple = new Tuple<String, Object, double, float, Tuple<String, String>>(
            "foo", "bar", 34.56, 5.43f, new Tuple<string, string>("Fred", "Barney"));

        tuple.GetPublicPropertiesWithValues().ForEach(p => Console.WriteLine(p));

        Console.ReadKey();
    }
}

输出:

(Item1, System.String, foo)
(Item2, System.Object, bar)
(Item3, System.Double, 34.56)
(Item4, System.Single, 5.43)
(Item5, System.Tuple`2[System.String,System.String], (Fred, Barney))

【讨论】:

    猜你喜欢
    • 2018-09-30
    • 2015-03-08
    • 2020-01-31
    • 2021-12-02
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多