2

Why does the code below give me the exception:

CSC error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

On my build server?

/// Customer.cs...

[Search(SearchAttribute.SearchDisplay.Regular)] 
public Category Category
{
     get; set;
}

public enum Category : byte
{
    X = 0x01,
    Y = 0x02,
    ...
}

/// SearchAttribute.cs...

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class SearchAttribute : Attribute
{
    public SearchDisplay Display { get; private set; }

    public enum SearchDisplay
    {
        None = (byte) 0x01,
        Regular = (byte) 0x02
    }

    public SearchAttribute(SearchDisplay display, string columnName = null)
        : base()
    {
        Display = display;
    }
}

Many Thanks.

Infuriatingly, it builds fine in VS2012. I'm unsure what version of the compiler runs on the server - but I'm fairly sure it's not the 2012 one.

UPDATE

Thanks to the answerers below I've figured this out:

I am using VS2012, but the build server is still using the VS2010 build process. There is a bug in the VS2010 / C#4 compiler that occurs when a null valued default parameter is used in an attribute. I can get around this 3 ways:

  1. Don't use a default parameter - public SearchAttribute(SearchDisplay display, string columnName)
  2. Use a empty string - public SearchAttribute(SearchDisplay display, string columnName = "")
  3. Update my build server.

I am going with 2 just now. 3 is something that I will need to think about at another time.

Community
  • 1
  • 1
Kev
  • 2,656
  • 3
  • 39
  • 63
  • 1
    See these related threads: http://stackoverflow.com/questions/8290853/attribute-argument-must-be-a-constant-error-when-using-an-optional-parameter-in http://stackoverflow.com/questions/3436848/default-value-for-attribute-constructor http://stackoverflow.com/questions/8189807/attributes-and-named-optional-constructor-parameters-not-working http://stackoverflow.com/questions/15048847/attribute-argument-must-be-a-constant-expression Apparently it's a bug that is now solved. Works with VS2010 for me. There must be some hotfix installed which your build server doesn't have. – Jeppe Stig Nielsen Apr 08 '13 at 17:01

2 Answers2

3

I think the Customer.cs file is in a separate assembly (C# project), and that assembly references the assembly (project) in which SearchAttribute.cs is located.

For the enum SearchDisplay and the optional parameter columnName in the constructor to work correctly, it is then vital that both assemblies are recompiled in the correct order. I suspect that wasn't the case on your build server. The dependent assembly was probably compiled with a reference to an old version of the assembly where SearchAttribute is located.

UPDATE

See all the linked threads on the right. This is a bug that they say is fixed with Visual Studio 2012 (C# 5 compiler). It happens only when the default value of the optional parameter is null. In my first test I made the silly decision to use another string (which would be recognizable), but it doesn't happen with another string. (Will erase my comment below.)

When the usage of the attribute is in the same assembly as the the attribute class itself, it helps to give the null literal an explicit type, as in:

public SearchAttribute(SearchDisplay display, string columnName = (string)null)
...

With this, it seems to work as long as all usages are in the same assembly as the above construtor. However, in your case they are in different assemblies.

Problem goes away if you are willing to use the empty string instead:

public SearchAttribute(SearchDisplay display, string columnName = "")
...

Otherwise, I suggest you use the old pre-C#-4-style

[Search(SearchAttribute.SearchDisplay.Regular)] 
public Category Category
...

[Search(SearchAttribute.SearchDisplay.Regular, ColumnName = "Changed!")] 
public Category AnotherCategory
...

This works with no columnName parameter in the constructor, as long as there's a class member (instance property or field) called ColumnName. That ColumnName must not be read-only or get-only.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • You are absolutely correct. Was the error nothing to do with the code, but simply build order? Or is Daniel A. White correct too? – Kev Apr 08 '13 at 16:22
  • @Kryptonite I'm not sure if it's supported. I would think it was, but the thread [Attributes and Named/Optional constructor parameters not working](http://stackoverflow.com/questions/8189807/) confuses me a bit. – Jeppe Stig Nielsen Apr 08 '13 at 16:24
  • @Kryptonite Update: Other threads here on Stack Overflow agree it's a bug. See my edited answer above. – Jeppe Stig Nielsen Apr 08 '13 at 17:25
1

Don't you mean

 [Search(SearchAttribute.SearchDisplay.Regular)] 
Daniel A. White
  • 187,200
  • 47
  • 362
  • 445