10

How can I pass a List to a construtor?

It shows a message:

Error 14 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

public class CustomAuthorize : AuthorizeAttribute {
    private List<string> multipleProgramID;

    //constructor
    public CustomAuthorize(List<string> _multipleProgramID) {
        multipleProgramID = _multipleProgramID;
    }
}

[CustomAuthorize(new List<string>(new string[] { ProgramList.SURVEY_INPUT, ProgramList.SURVEY_OUTPUT } ))]
[HttpPost]
public ActionResult DeleteWaterQualityItems(string sourceID, string wqID) {
    // ..other code...
}

public class ProgramList {
    public const string SURVEY_INPUT = "A001";
    public const string SURVEY_INPUT = "A002";
}

5 Answers 5

19

The problem isn't passing a List<string> to a constructor in general - the problem is that you're trying to use it for an attribute. You basically can't do that, because it's not a compile-time constant.

It looks like ProgramList is effectively an enum - so you might want to make it an enum instead:

 [Flags]
 public enum ProgramLists
 {
     SurveyInput,
     SurveyOutput,
     ...
 }

Then make your CustomAuthorizeAttribute (which should be named like that, with a suffix of Attribute) accept a ProgramLists in the constructor. You'd specify it as:

[CustomAuthorize(ProgramLists.SurveyInput | ProgramLists.SurveyOutput)]

You can then have a separate way of mapping each ProgramLists element to a string such as "A001". This could be done by applying an attribute to each element, or maybe having a Dictionary<ProgramLists, string> somewhere.

If you really want to keep using strings like this, you could make CustomAuthorizeAttribute accept a single comma-separated list, or make it an array instead of a list and use a parameter array:

[AttributeUsage(AttributeTargets.Method)]
public class FooAttribute : Attribute
{
    public FooAttribute(params string[] values)
    {
        ...
    }
}

[Foo("a", "b")]
static void SomeMethod()
{
}
Sign up to request clarification or add additional context in comments.

3 Comments

in 2020, is this still to way to go?
@curiousBoy: Yes, attributes still can't use lists.
And in 2021 I presume it's still the case. If anyone has a better way please add it as an answer. Thank You.
8

You can't use List<T>.

Attributes have restrictions on parameters and property types, because they have to be available at compile-time. Using attributes in C#

Use an array instead:

//constructor
public CustomAuthorize(string[] _multipleProgramID) 
{
    ...
}

// usage
[CustomAuthorize(new string[] { ProgramList.SURVEY_INPUT, ProgramList.SURVEY_OUTPUT })]

3 Comments

The compiler suggests this is possible - but for some reason this exact code (with string rather than enum) didn't work for me :( I got the same error about only being able to use constant expressions, types and array initializers - which is exactly what I was doing! Had to use a string split, as suggested by @blues_driven.
just tried it and it does compile in VS 2017, but it doesn't have to work for me - it has to work for you :-)
I was trying to pass a string array argument as a NUnut TestCase parameter. [TestCase(new string[] {"a"})] public void TestMethod(string[] ab) - this gives me Error CS0182 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type. And I've just worked out why. It couldn't work out which parameter I was trying to pass - If I make an object array WHICH CONTAINS my string array it works: [TestCase(new object[] { new string[] { "a" } })]
2

I was trying to do something similar and ended up passing a comma separated string and using string.Spilt(',') in the attribute constructor to convert it to an array.

Comments

2

You just need to use "params" keyword in your custom attribute constructor and make your programList "enum"

[CustomAttribute(ProgramList.SURVEY_INPUT, ProgramList.SURVEY_OUTPUT)]
[HttpPost]
public ActionResult DeleteWaterQualityItems(string sourceID, string wqID) {
    // ..other code...
}

in you custom attribute class use this

public class CustomAuthorize : AuthorizeAttribute {

//Constructor
public CustomAuthorize (params ProgramList[] programListTypes) {

            multipleProgramID= programListTypes;
        }

private ProgramList[] multipleProgramID;

}

and you enum class

public enum ProgramList : int
{
SURVEY_INPUT = 001;
SURVEY_OUTPUT =002;

}

Comments

0

One possible option:

   public class ConstraintExpectedValues : ConstraintAttribute
    {

        public ConstraintExpectedValues(object[] expectedValues)
        {
            this.ExpectedValues = expectedValues;
        }

        public object[] ExpectedValues { get; set; }
    }

Usage:

[ConstraintExpectedValues(new object[] {5,7,9})]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.