Create const string array in C #

2

Is there a way to create a constant array of string ?

Something like:

class Teste
{
    public const string[] Array = new string[] {"a","b"};
}

But it does not compile.

In this case no would replace const with static readonly because I need to use it as an Attribute parameter.

[CustomAttribute(Teste.Array)]
public void Metodo(){ ... }

Doing this I have the following exception:

  

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

Then it must be const . Is there a way to do this in C #?

    
asked by anonymous 10.09.2015 / 19:01

4 answers

2

There is no way to do this. The only feasible solution is to change the information.

For the example shown, you can use a simple string . If you have only one character, each will be an element, if each can have more characters, provide a separator for each substring . Of course, you have to treat this string properly to get the parts. The details may be best thought of, but it is the only way, in a general way, that I know.

public class Teste {
    public const string Array = "a,b,c,d,...";
}

I found a solution for the case of being numeric . Note that an enumeration has given way to array .

This restriction is precisely to not allow you to do what you want.

You may not understand the use of const . When it is used it means you should no longer change the value of it throughout the life of the application. Of course it can even change, but it would have to recompile everything, including what depends on this constant, which is not guaranteed to happen. Even if it is your case, the compiler will not allow since the CLR does not allow (it must be possible to save the data in metadata , so it can not have code).

Or you can use the array in the attribute itself, which is not what you want, but is another way.

Specification:

  

§24.1.3 Attribute parameter types

     

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

     
  • One of the following types: bool, byte, char, double, float, int,   long, short, string.
  •   
  • The type object.
  •   
  • The type System.Type.
  •   
  • An enum type, provided it has public accessibility and the types in which it   is nested (if any) also have public accessibility.
  •   
  • Single-dimensional arrays of the above types.
  •   
    
10.09.2015 / 19:41
1

Solution

Since an attribute accepts a Type as a parameter (as long as this Type in>), you can use "creativity."

Then you need atributte to get a string array as a parameter but do not want to tell this array every time you decorate a member with this atributte , so you you want to get this array from a declaration elsewhere, a statement that you can change in the future or in some particular use of your attribute .

In order to have different declarations of the array that will be passed as parameter to the attribute, you can declare an interface:

interface IAttributeArgument
{
    string[] Argument { get; }
}

Declare one of the arrays that can be used as your attribute parameter declaring a class that implements this interface:

class AttributeArgument : IAttributeArgument
{
    public string[] Argument { get { return new string[] { "a", "b", "c" }; } }
}

Now the array can be passed as a parameter to your attribute like this:

    [CustomAttribute(typeof(AttributeArgument))]
    public void Metodo() { }

In your attribute implementation, you can create a Type instance passed by parameter and read the array like this:

class CustomAttribute : Attribute
{
    public Type attributeArgument;

    public CustomAttribute(Type attributeArgument)
    {
        this.attributeArgument = attributeArgument;
    }
    public string[] Argument
    {
      get 
      { 
        return ((IAttributeArgument)Activator.CreateInstance(attributeArgument)).Argument; 
      }
    }
}

Tip: attributes are metadata declarations

This solution, as well as any other you find for what you want to do, is a swarm. See for example that attribute would accept any Type but wish to receive only a specific Type bad.

There is a reason for Attributes to accept a limited range of types as a parameter, and the reason is that atributte is a metadata declaration.

I repeat: statement . Decorating a member with an atributte adds metadata to it that should be able to be understood immediately by the programmer without having to resort to other points in the code.

That is, the ideal (expressive) way of passing parameters to an attribute is either a literal value or the expression of a literal value, such as a constant or an Enum .

An example of what would be an expressive use of attributes :

public class LinhaLidaDoArquivoTexto
{
    [ColunaTipoData(ordem: 1, formatoData: "dd-MM-yyyy")]
    public DateTime DataEnvio { get; set; }

    [ColunaTipoDecimal(ordem: 2, formatoDecimal: "#0.00")]
    public decimal ValorEnviado { get; set; }

    ...
}

The parameters passed to the attribute are not meant to be "variables". They are helping to express the class metadata expressively.

    
10.09.2015 / 20:14
1

Workaround: Enumeration

class Teste
{
    public enum Array = {a, b};
}

So, the stretch

[CustomAttribute(Teste.Array)]
public void Metodo(){ ... }

will allow compilation.

If you need to extract the name of the item listed as string , use Enum.GetName() .

    
11.09.2015 / 14:44
1

If the intent is to reuse the value I believe that the best alternative is the use of Inheritance.

Considering the

public class CustomAttribute : Attribute
    public string[] Valor{get;set;}

    public CustomAttribute(string[] Valor)
    {
        this.Valor = Valor;
    }
}

You can create a new one by inheriting it and passing the values you want

public class CustomABAttribute : CustomAttribute
{
    public CustomABAttribute()
        : base(new[] {"a", "b"})
    {
    }
}

So using this new attribute any code that looks for an attribute of type CustomAttribute should find this new one that was created

[CustomAB()]
public void Metodo(){ ... }
    
11.09.2015 / 14:58