LINQ 查询中奇怪的扩展方法行为

Weird extention method behaviour in LINQ query

我有一个自定义属性,用于存储枚举项的显示名称。我写了一个扩展方法,returns 枚举自定义属性显示名称。

我在 LINQ 查询中使用我的扩展方法。但输出很奇怪。当我在尚未 运行 的查询中调用我的扩展方法时,它 returns Enum is null 但是当我 运行 它在查询中调用 .ToList() ,它工作正常(见输出)... 他们之间有什么不同?为什么当我的查询不 运行..

时枚举为空

注意:我是 LINQPAD

void Main()
{
    Console.WriteLine(((ProductStatuses)0).GetTitle());
    Console.WriteLine(((ProductStatuses)1).GetTitle());
    Console.WriteLine(((ProductStatuses)3).GetTitle());

    var query_01 = (from item in SH_Products
                    select new
                    {
                        Status = item.Status,
                        StatusText = ((ProductStatuses)item.Status).GetTitle(),
                    });

    var query_02 = (from item in SH_Products.ToList()
                    select new
                    {
                        Status = item.Status,
                        StatusText = ((ProductStatuses)item.Status).GetTitle(),
                    });

    query_01.Dump();
    query_02.Dump();
}

public static class ExtensionMethods
{
    public static string GetTitle(this Enum enm)
    {
        if (enm == null)
        {
            return "Enum is null";
        }

        var type = enm.GetType();
        var members = type.GetMembers(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);

        foreach (var item in members)
        {
            if (enm.ToString() == item.Name)
            {
                var attributes = item.GetCustomAttributes(typeof(FaraDisplay), false);

                var attribute = String.Empty;
                if (attributes.Length == 0)
                    attribute = item.Name;
                else
                    attribute = ((FaraDisplay)attributes.Single()).GetName();

                return attribute;
            }
        }

        throw new InvalidEnumArgumentException();
    }
}

public enum ProductStatuses
{
    [FaraDisplay("Inactive Product")]
    Inactive = 0,
    [FaraDisplay("Available Product")]
    Available = 1,
    [FaraDisplay("ComingSoon Product")]
    ComingSoon = 2,
    [FaraDisplay("UnAvailable Product")]
    UnAvailable = 3,
    [FaraDisplay("OrderRegister Product")]
    OrderRegister = 4
}

[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class FaraDisplay : Attribute
{
    private readonly string _name;

    public FaraDisplay(string name)
    {
        _name = name;
    }

    public string GetName()
    {
        return _name;
    }
}

输出:

Inactive Product
Available Product
UnAvailable Product

Enum is null
Enum is null
Enum is null
Enum is null

Inactive Product
Available Product
UnAvailable Product
UnAvailable Product

实际上问题是 linq to sql 不知道如何将 GetTiltle() 翻译成 sql 语句,因此它会跳过它。当您调用 ToList() 时,您正在对对象使用 linq,因此它按预期工作,因为此时它只是普通的 ol'.net。

所有 linq 提供程序(entity framework、nhibernate 等)都有同样的问题,尽管您会看到 entity framework 抛出异常,nhibernate 也可能如此。

没有基于您正在做的事情的解决方法,所以一旦您将对象存储在内存中,您就必须进行该计算。

在 Linq 查询中,您不应该使用方法调用,而应该先获取值,然后在 Linq 查询中赋值,我认为 Darren 是正确的。