1

I have a custom attribute that stores display name of an Enum item. I write an Extension method that returns of Enum custom attribute display name.

I use my Extension method in a LINQ query. but the output is weird. When I call my extention method in a query that doesn't run yet, it returns Enum is null but when I run it in query that .ToList() is called, it works fine (see output)... what is different between them? Why enum is null when my query doesn't run..

Note: I'm 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;
    }
}

output:

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

Mohamad Shiralizadeh
  • 8,329
  • 6
  • 58
  • 93

2 Answers2

9

Effectively the problem is that linq to sql doesn't know how to translate GetTiltle() into a sql statement, so it skips it. When you call ToList(), you are using linq to objects, so it works as expected because it's just plain ol' .net at that point.

All linq providers (entity framework, nhibernate, etc) have this same problem, though you will see entity framework throw an exception, and perhaps nhibernate as well.

There isn't a way around it based on what you are doing, so you'll just have to do that calculation once you have the objects in memory.

Darren Kopp
  • 76,581
  • 9
  • 79
  • 93
0

inside Linq queries you should not be using method calls instead you should get the value out first and then assign inside the linq query I think Darren is correct.

pubudut
  • 603
  • 2
  • 8
  • 18