首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >检测对象是否为ValueTuple

检测对象是否为ValueTuple
EN

Stack Overflow用户
提问于 2017-10-12 10:40:58
回答 4查看 4.7K关注 0票数 15

我有一个用例,在这个用例中,我需要检查一个值是否是C# 7 ValueTuple,如果是的话,循环遍历每个项。我试过使用obj is ValueTupleobj is (object, object)进行检查,但这两种方法都返回false。我发现我可以使用obj.GetType().Name,并检查它是否以"ValueTuple"开头,但在我看来,这似乎很糟糕。欢迎任何替代办法。

我也有问题,得到每一个项目。我试图用这里找到的解决方案获得Item1How do I check if a property exists on a dynamic anonymous type in c#?,但((dynamic)obj).GetType().GetProperty("Item1")返回null。我的希望是,然后我可以做一个while,以获得每一项。但这行不通。我怎样才能得到每一件物品?

更新-更多代码

代码语言:javascript
复制
if (item is ValueTuple) //this does not work, but I can do a GetType and check the name
{
    object tupleValue;
    int nth = 1;
    while ((tupleValue = ((dynamic)item).GetType().GetProperty($"Item{nth}")) != null && //this does not work
        nth <= 8)      
    {
        nth++;
        //Do stuff
    }
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-10-12 11:54:27

这是我解决问题的办法。与PCL兼容的扩展类。特别感谢@dasblinkenlight和@Evk帮助我!

代码语言:javascript
复制
public static class TupleExtensions
{
    private static readonly HashSet<Type> ValueTupleTypes = new HashSet<Type>(new Type[]
    {
        typeof(ValueTuple<>),
        typeof(ValueTuple<,>),
        typeof(ValueTuple<,,>),
        typeof(ValueTuple<,,,>),
        typeof(ValueTuple<,,,,>),
        typeof(ValueTuple<,,,,,>),
        typeof(ValueTuple<,,,,,,>),
        typeof(ValueTuple<,,,,,,,>)
    });

    public static bool IsValueTuple(this object obj) => IsValueTupleType(obj.GetType());
    public static bool IsValueTupleType(this Type type)
    {
        return type.GetTypeInfo().IsGenericType && ValueTupleTypes.Contains(type.GetGenericTypeDefinition());
    }

    public static List<object> GetValueTupleItemObjects(this object tuple) => GetValueTupleItemFields(tuple.GetType()).Select(f => f.GetValue(tuple)).ToList();
    public static List<Type> GetValueTupleItemTypes(this Type tupleType) => GetValueTupleItemFields(tupleType).Select(f => f.FieldType).ToList();    
    public static List<FieldInfo> GetValueTupleItemFields(this Type tupleType)
    {
        var items = new List<FieldInfo>();

        FieldInfo field;
        int nth = 1;
        while ((field = tupleType.GetRuntimeField($"Item{nth}")) != null)
        {
            nth++;
            items.Add(field);
        }

        return items;
    }
}
票数 6
EN

Stack Overflow用户

发布于 2017-10-12 10:52:12

结构在C#中不继承,因此ValueTuple<T1>ValueTuple<T1,T2>ValueTuple<T1,T2,T3>等是不同的类型,它们不以ValueTuple作为它们的基础。因此,obj is ValueTuple检查失败。

如果要查找具有任意类型参数的ValueTuple,可以检查类是否为ValueTuple<,...,>,如下所示:

代码语言:javascript
复制
private static readonly Set<Type> ValTupleTypes = new HashSet<Type>(
    new Type[] { typeof(ValueTuple<>), typeof(ValueTuple<,>),
                 typeof(ValueTuple<,,>), typeof(ValueTuple<,,,>),
                 typeof(ValueTuple<,,,,>), typeof(ValueTuple<,,,,,>),
                 typeof(ValueTuple<,,,,,,>), typeof(ValueTuple<,,,,,,,>)
    }
);
static bool IsValueTuple2(object obj) {
    var type = obj.GetType();
    return type.IsGenericType
        && ValTupleTypes.Contains(type.GetGenericTypeDefinition());
}

要根据类型获取子项,您可以使用一种不是特别快的方法,但是应该能做到这一点:

代码语言:javascript
复制
static readonly IDictionary<Type,Func<object,object[]>> GetItems = new Dictionary<Type,Func<object,object[]>> {
    [typeof(ValueTuple<>)] = o => new object[] {((dynamic)o).Item1}
,   [typeof(ValueTuple<,>)] = o => new object[] {((dynamic)o).Item1, ((dynamic)o).Item2}
,   [typeof(ValueTuple<,,>)] = o => new object[] {((dynamic)o).Item1, ((dynamic)o).Item2, ((dynamic)o).Item3}
,   ...
};

这会让你这么做:

代码语言:javascript
复制
object[] items = null;
var type = obj.GetType();
if (type.IsGeneric && GetItems.TryGetValue(type.GetGenericTypeDefinition(), out var itemGetter)) {
    items = itemGetter(obj);
}
票数 13
EN

Stack Overflow用户

发布于 2017-11-03 12:56:48

关于“我怎样才能得到每一件东西”这部分问题?

ValueTuple和Tuple都实现了ITuple,后者具有length属性和indexer属性。因此,下面的控制台应用程序代码列出控制台的值:

代码语言:javascript
复制
// SUT (as a local function)
IEnumerable<object> GetValuesFromTuple(System.Runtime.CompilerServices.ITuple tuple) 
{
    for (var i = 0; i < tuple.Length; i++)
        yield return tuple[i];
}

// arrange
var valueTuple = (StringProp: "abc", IntProp: 123, BoolProp: false, GuidProp: Guid.Empty);

// act
var values = GetValuesFromTuple(valueTuple);

// assert (to console)
Console.WriteLine($"Values = '{values.Count()}'");

foreach (var value in values)
{
    Console.WriteLine($"Value = '{value}'");
}

控制台输出:

代码语言:javascript
复制
Values = '4'
Value = 'abc'
Value = '123'  
Value = 'False'  
Value = '00000000-0000-0000-0000-000000000000'
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46707556

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档