【问题标题】:Expression of type 'MyEnum' cannot be used for parameter of type'MyEnum' 类型的表达式不能用于类型参数
【发布时间】:2013-02-01 17:18:48
【问题描述】:

我为我的枚举创建了 Enum ToFrendlyString 函数,但我不能在 Linq 中使用。

 public enum MyEnum
    {

        Queued = 0,           
        [Description("In progress")]
        In_progress = 2,            
        [Description("No answer")]
        No_answer = 6,

    }



  public static class EnumToFrendlyString
    {

        public static string ToFrendlyString(this Enum value)
        {
            return value.GetEnumDescription();
        }


        public static string GetEnumDescription(this Enum value)
        {
            FieldInfo fi = value.GetType().GetField(value.ToString());

            var attributes =
                (DescriptionAttribute[])fi.GetCustomAttributes(
                    typeof(DescriptionAttribute),
                    false);

            if (attributes.Length > 0)
                return attributes[0].Description;

            return value.ToString();
        }
    }

当我尝试在 Linq 中使用这个函数时,我得到了错误

  var res = collection.AsQueryable().Where(p => p.UserID == UserID).OrderByDescending(p=> p.DateCreated).Select(p => new MyClass
                {                          
                     Date = p.DateCreated.ToString(),
                     Status = p.Status.ToFrendlyString(),                        
                }).Take(10).ToList();

如果我在同一个类中创建另一个函数,比如

 private string MyStatusToString(MyEnum status)
       {
           return status.ToFrendlyString();
       }

并更改我的 Linq 以使用此功能,然后一切正常。

错误

Expression of type 'DAL.MyEnum' cannot be used for parameter of type 'System.Enum' of method 'System.String ToFrendlyString(System.Enum)'

【问题讨论】:

  • 当你有一个非常好的数字枚举时,为什么要查询字符串状态?
  • 您的错误引用了MyEnum,但您的枚举是MyStatusp.Status 真的是枚举类型吗?
  • @Trickery, couze 我将该结果作为 ajax 返回,我不想让 JS 逻辑呈现为字符串。
  • @MikeC 有写入错误,我重命名了我的课程等等,现在编辑不好
  • 您的代码对我来说很好用。您能否包含显示问题的简短但完整的示例代码? collection的类型是什么?

标签: c# linq enums extension-methods


【解决方案1】:

我不确定您是否可以将 Enum 用作此类扩展方法的类型 - 请改用此方法。我冒昧地整理了一下代码,请随意忽略这些更改 :)

public static class EnumToFrendlyString
{
    public static string ToFrendlyString<T>(this T value)
        where T : struct
    {
        return value.GetEnumDescription();
    }

    public static string GetEnumDescription<T>(this T value)
        where T : struct
    {
        return EnumDescriptionCache<T>.Descriptions[value];
    }

    private static class EnumDescriptionCache<T>
        where T : struct
    {
        public static Dictionary<T, string> Descriptions =
            Enum.GetValues(typeof(T))
                .Cast<T>()
                .ToDictionary(
                    value => value,
                    value => value.GetEnumDescriptionForCache());
    }

    private static string GetEnumDescriptionForCache<T>(this T value)
        where T : struct
    {
        if (!typeof(T).IsEnum)
        {
            throw new ArgumentException("Only use with enums", "value");
        }

        var descriptionAttribute = typeof(T)
            .GetField(value.ToString())
            .GetCustomAttributes(typeof(DescriptionAttribute), false)
            .Cast<DescriptionAttribute>()
            .FirstOrDefault();

        return (descriptionAttribute != null)
            ? descriptionAttribute.Description
            : value.ToString();
    }
}

我添加了一个私有的通用类来缓存枚举成员的描述,以避免在运行时大量使用反射。它看起来有点奇怪进出类首先缓存然后检索值,但它应该可以正常工作:)

我在 this answer 中给出的警告仍然适用 - 传递给字典的枚举值未经过验证,因此您可以通过调用 ((MyEnum)5367372).ToFrendlyString() 使其崩溃。

【讨论】:

  • 可以在类似的扩展方法中使用Enum
  • 哇哇,看起来它工作正常!如果我不评论任何错误,那么它 100% 工作。你能解释一下为什么“where T : struct”在这里发挥作用吗?关于缓存,由于它的通用功能,我是否必须在第一次 ToFrendlyString 调用时缓存,因为我如何初始化缓存字典?
  • where T : struct 只是限制了扩展方法对值类型的适用性——没有它,这个方法应该可以正常工作。正如@svick 指出的那样,您实际上 can 使用 Enum 作为扩展方法的类型,所以老实说,我不能 100% 确定它为什么不起作用当你这样做的时候。我将使用缓存示例更新答案:)
【解决方案2】:

我不确定,但可能是您尚未将 DAL 项目添加到当前项目中(添加参考 -> 解决方案中的项目 -> Dal)。那么它可能会起作用。 (我曾经遇到过类似的问题,这是我的解决方案)

【讨论】:

  • 已经添加,如果没有,Resharper 或 Build fill 会提示错误
  • 并非总是如此。我有一个带有 Enum 的构造函数,但该项目没有在引用中添加项目(带有 neum),它只在运行时给出了相同的错误错误。添加引用为我修复了它。
【解决方案3】:

问题似乎在于您的集合是 IQueryable&lt;T&gt;,而查询提供程序正试图将您的 Select() 转换为查询字符串。

避免这种情况的一种方法是使用IEnumerable&lt;T&gt;在内存中执行Select()

var res = collection.AsQueryable()
            .Where(p => p.UserID == UserID)
            .OrderByDescending(p=> p.DateCreated)
            .Take(10)
            .AsEnumerable()
            .Select(p => new MyClass
            {                          
                 Date = p.DateCreated.ToString(),
                 Status = p.Status.ToFrendlyString(),                        
            })
            .ToList();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-10-23
    • 2011-01-13
    • 2013-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多