如何将对整数有效的通用表达式树代码应用于枚举(例如如何使Expression.PostIncrementAssign()对枚举起作用?)? [英] How to apply generic expression-trees code that works well on integers, to enums (e.g. how to make Expression.PostIncrementAssign() work on enums?)?

查看:81
本文介绍了如何将对整数有效的通用表达式树代码应用于枚举(例如如何使Expression.PostIncrementAssign()对枚举起作用?)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个扩展方法来做到这一点:

I'm trying to create an extension method to do this:

enum AlphaBet { A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z }

IEnumerable<AlphaBet> rangeCtoG = AlphaBet.C.RangeToInc(AlphaBet.G);

但这不会编译(因为TEnum是通用的):

But this won't compile (as TEnum is generic):

public static IEnumerable<TEnum> RangeToInc<TEnum>(this TEnum from, TEnum to)
    where TEnum : struct, IComparable, IFormattable, IConvertible //
{
    for (; from <= to; from++)
        yield return from;
}

所以我转向表达式:

public delegate void MyFunc<T>(ref T arg); // allow PostIncrementAssign to change the input parameter

public static IEnumerable<TEnum> RangeToInc<TEnum>(this TEnum from, TEnum to)
    where TEnum : struct, IComparable, IFormattable, IConvertible //
{
    var fromRefParamExpr = Expression.Parameter(typeof(TEnum).MakeByRefType(), "fromParam");
    var incrementExpr = Expression.PostIncrementAssign(fromRefParamExpr);
    var increment = Expression.Lambda<MyFunc<TEnum>>(incrementExpr, fromRefParamExpr).Compile();

    var fromParamExpr = Expression.Parameter(typeof(TEnum), "fromParam");
    var toParamExpr = Expression.Parameter(typeof(TEnum), "toParam");
    var lessThanOrEqualExpr = Expression.LessThanOrEqual(fromParamExpr, toParamExpr);
    var lessThanOrEqual = Expression.Lambda<Func<TEnum, TEnum, bool>>(
        lessThanOrEqualExpr, toParamExpr, fromParamExpr).Compile();

    for (; lessThanOrEqual(to, from); increment(ref from))
        yield return from;
}

它适用于整数,但不适用于枚举:行Expression.PostIncrementAssign(fromRefParamExpr)失败,并带有异常:

It works great with integers, but not with enums: the line Expression.PostIncrementAssign(fromRefParamExpr) fails with exception:

System.InvalidOperationException:
    'The unary operator PostIncrementAssign is not defined for the type
    '...+AlphaBet'.'

哪个令人惊讶-enum不是数字类型吗?我应该做些什么?来回投射enumint?

Which is quite suprising - isn't an enum a numeric type? what am I supposed to do? cast back and forth enumint?

推荐答案

也许这可以为您提供帮助.

maybe this is can help you..

    public static IEnumerable<TEnum> RangeToInc<TEnum>(this TEnum from, TEnum to) where 
        TEnum : struct, IComparable, IFormattable, IConvertible
    {
        return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Where(
            a => a.CompareTo(from) >= 0 
                && a.CompareTo(to) <= 0).ToArray(); //Actually it does not need ToArray


    }

可扩展性更高

    public static IEnumerable<TEnum> RangeToInc<TEnum>(this TEnum from, TEnum to) where
        TEnum : struct, IComparable, IFormattable, IConvertible
    {
        if (typeof(TEnum).IsEnum)
            return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Where(
                a => a.CompareTo(from) >= 0
                    && a.CompareTo(to) <= 0);
        else if (typeof(TEnum).IsNumericType())
        {
            int start = Convert.ToInt32(from);
            int count = Convert.ToInt32(to) - start;
            return Enumerable.Range(start, count + 1).Cast<TEnum>();
        }

        throw new NotImplementedException();
    }
    public static bool IsNumericType(this Type type)
    {
        switch (Type.GetTypeCode(type))
        {
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.Decimal:
            case TypeCode.Double:
            case TypeCode.Single:
                return true;
            default:
                return false;
        }
    }

使用

        IEnumerable<DayOfWeek> enumRange = DayOfWeek.Sunday.RangeToInc(DayOfWeek.Wednesday);
        foreach (var item in enumRange)
        {
            Console.Write(item + " ");
            //
        }
        Console.WriteLine();
        int a = 4;
        var intRange = a.RangeToInc(10);
        foreach (var item in intRange)
        {
            Console.Write(item + " ");
        }
        //output 
        // Sunday Monday Tuesday Wednesday
        // 4 5 6 7 8 9 10

这篇关于如何将对整数有效的通用表达式树代码应用于枚举(例如如何使Expression.PostIncrementAssign()对枚举起作用?)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆