How to Initialize a C# Attribute with an Array or Other Variable Number of Arguments

Can I initialize a C# attribute with an array or other variable number of arguments?

Attributes will take an array. Though if you control the attribute, you can also use params instead (which is nicer to consumers, IMO):

class MyCustomAttribute : Attribute {
public int[] Values { get; set; }

public MyCustomAttribute(params int[] values) {
this.Values = values;
}
}

[MyCustomAttribute(3, 4, 5)]
class MyClass { }

Your syntax for array creation just happens to be off:

class MyCustomAttribute : Attribute {
public int[] Values { get; set; }

public MyCustomAttribute(int[] values) {
this.Values = values;
}
}

[MyCustomAttribute(new int[] { 3, 4, 5 })]
class MyClass { }

Can I use a collection initializer for an Attribute?

Update: I'm sorry I'm mistaken - pass array of custom type is impossible :(

The types of positional and named parameters for an attribute class
are limited to the attribute parameter types, which are:

  1. One of the following types: bool, byte, char, double, float,
    int, long, short, string
    .
  2. The type object.
  3. The type System.Type.
  4. An Enum type, provided it has public accessibility and the types
    in which it is nested (if any) also have public accessibility (Section
    17.2).
  5. Single-dimensional arrays of the above types.
    source

Source: stackoverflow.

You CAN DECLARE passing an array of a custom type:

class TestType
{
public int Id { get; set; }
public string Value { get; set; }

public TestType(int id, string value)
{
Id = id;
Value = value;
}
}

class TestAttribute : Attribute
{
public TestAttribute(params TestType[] array)
{
//
}
}

but compilation errors occur on the attribute declaration:

[Test(new[]{new TestType(1, "1"), new TestType(2, "2"), })]
public void Test()
{

}

C# Custom Attribute parameters

The accepted answer uses the public property instead of a private field. The benefit of public property is you can omit the constructor and supply the values of the properties in the default constructor.

I change your first code, the one with public property, to something like this.

class MyCustomAttribute : Attribute {
public int[] Values { get; set; }
}

[MyCustomAttribute(Values = new int[] { 3, 4, 5 })]
class MyClass { }

Function with variable number of arguments

Yes you can write something like this:

void PrintReport(string header, params int[] numbers)
{
Console.WriteLine(header);
foreach (int number in numbers)
Console.WriteLine(number);
}

How do I set a constructor's parameters to an array of variable size?

I think you're somewhat confused. char[] wordToGuessArray = wordToGuess.ToCharArray(); is not only allocating the correct size array for you, it's also filling it with the contents of wordToGuess I have two suggested changes to make your code better.

public char[] selectWord()
{
// get rid of size in this, when you do static init you don't need it
String[] hangmanWords = new String[] { "time", "person", "year", "way", "day", "thing", "man", "world", "life", "hand", "part", "child", "eye", "woman", "place", "work", "week", "case", "point", "government", "company", "number", "group", "problem", "fact", "good", "new", "first", "last", "long", "great", "little", "own", "other", "old", "right", "big", "high", "different", "small", "large", "next", "early", "young", "important", "few", "public", "bad", "same", "able" };
// combinme those bottom 5 or so lines into 1.
return hangmanWords[new Random.Next(0, 49)].ToUpper().ToCharArray();
}

This method will simply return a character array which has the characters of a randomly selected word from the hangmanWords array. I believe that's what you want, right?

If you want the character array wordToGuessArray to be a property of your class then just declare it as public char[] wordsToGuessArray { get; set; } and make the method void, replacing the return with assingment to wordsToGuessArray.

Sample constructor;

 // field declared in my class, call it game
public char[] wordsToGuessArray { get; set; }

public Game(char[] word)
{
wordToGuessArray = word;
}
// call it like this
Game game = new Game(selectWord());

If you want to set wordToGuessArray in the constructor you can make selectWord() a public static method in the same class in which case you would call it like Game.selectWord()

How to declare and initialize multiple variables (with different names) within a for loop without using arrays?

You cannot create dynamically named variables in C# (and I am with those who are wondering why you want to do that). If you don't want to use an array, consider a Dictionary -- it would perform better than an array in some circumstances.

Dictionary<string, int> values = new Dictionary<string, int>();
for (int i = 1; i <= 4; i++)
{
values.Add("value" + i, 0);
}

value["value1"]; //retrieve from dictionary

Passing static array in attribute

Unfortunately this is not possible. The attributes (including the values of their arguments) are placed into the assembly metadata by the compiler so it has to be able to evaluate them at compile time (hence the restriction to constant expressions; the exception for array creation expressions was obviously made because otherwise you could not have array arguments at all).

In contrast, the code that actually initializes A.Months is only executed at runtime.

How to put an array of enum in a authorize attribute?

enum.Value | enum.Value | enum.Value

What about flags?

Like this:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Constructor | AttributeTargets.Enum)]

Edit: By the way, there is very interesting answer: https://stackoverflow.com/a/270231/2524304

All possible array initialization syntaxes

These are the current declaration and initialization methods for a simple array.

string[] array = new string[2]; // creates array of length 2, default values
string[] array = new string[] { "A", "B" }; // creates populated array of length 2
string[] array = { "A" , "B" }; // creates populated array of length 2
string[] array = new[] { "A", "B" }; // created populated array of length 2

Note that other techniques of obtaining arrays exist, such as the Linq ToArray() extensions on IEnumerable<T>.

Also note that in the declarations above, the first two could replace the string[] on the left with var (C# 3+), as the information on the right is enough to infer the proper type. The third line must be written as displayed, as array initialization syntax alone is not enough to satisfy the compiler's demands. The fourth could also use inference. So if you're into the whole brevity thing, the above could be written as

var array = new string[2]; // creates array of length 2, default values
var array = new string[] { "A", "B" }; // creates populated array of length 2
string[] array = { "A" , "B" }; // creates populated array of length 2
var array = new[] { "A", "B" }; // created populated array of length 2

What syntax is allowed when applying C# attributes?

AFAIK, named parameters only permit integral types. Unfortunately i do not have a reference to back this up, I only learnt it through my own experimentation.

When trying to use object initialisers, I got this error from the compiler:

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

Although this documentation is a few years old, it has the reference information I was looking for:

Attribute parameters are restricted to constant values of the
following types:

  • Simple types (bool, byte, char, short, int, long, float, and double)
  • string
  • System.Type
  • enums
  • object (The argument to an attribute parameter of type object must be a constant value of one of the above types.) One-dimensional
    arrays of any of the above types

So this works:

//Test attribute class
[AttributeUsage(AttributeTargets.All)]
internal class TestAttribute : Attribute
{
public int[] Something { get; set; }
}

//Using an array initialiser - an array of integers
[TestAttribute(Something = new int[]{1, 2, 3, 4, 5})]
public abstract class Something

Whereas this wouldn't:

//Test person class
internal class Person
{
public string Name { get; set; }

public Person(string name)
{
this.Name = name;
}
}

//Test attribute class
[AttributeUsage(AttributeTargets.All)]
internal class TestAttribute : Attribute
{
public IEnumerable<Person> Something { get; set; }
}

//This won't work as Person is not an integral type
[TestAttribute(Something = new Person[]{new Person("James")})]

EDIT: just to elaborate, attributes form part of the metadata for constructs they are applied to (within the generated IL), thus the members of the attribute class must be determined at compile time; hence the restriction on attribute parameters to constant values.



Related Topics



Leave a reply



Submit