Create string array in C#

Asked

Viewed 1,114 times

3

There is a way to create an array of string constant?

Something like:

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

But this one doesn’t compile.

In this case nay would resolve to replace const for static readonly why I need to use it as an attribute parameter.

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

In doing so I have the following exception:

An attribute argument must be a Constant Expression, typeof Expression or array Creation Expression of an attribute Parameter type

So it needs to be const. There’s a way to do it in C#?

  • You can’t use [CustomAttribute({"a","b"})]?

  • Even for sure, but I’m in a great application and set all the values in the hand becomes unviable. I look for a way to encapsulate it

  • Because it needs to be a array? 'Cause it can’t be a string? You cannot change the way you use this attribute?

  • Because the values I need to pass on are more complex than that. The fact that it is an array is so you don’t have to pass dozens of strings in each attribute. Instead of passing [CustomAttribute("a","b","c","d",..."outros 20 valores")] I only inform the array. And if I need to change these items, I change only the array, and I don’t need to go out hunting code. As I said before: this is a great application, I can’t just put a string and leave it at that.

4 answers

3

There is no way to do that. The only viable solution is to change the information.

By the example shown it is possible to use a string simple. If you have only one character, each will be an element, if each can have more characters, provide a separator for each substring. Sure, you gotta take care of that string properly to pick up the pieces. The details may be better thought out, but it is the only way, generally speaking, that I know.

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

I found a solution in case it is numerical. Note that an enumeration has given rise to the array.

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

Maybe you don’t understand the use of const. When it is used it means that you should no longer change its value in the entire life of the application. Of course it can change, but you would have to recompile everything, including what depends on this constant, which is not guaranteed to happen. Even if this is your case, the compiler will not allow since the CLR does not allow it (it has to be possible to store the data in the Metadata, then you can’t 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.
  • I don’t intend to change this array after compilation, until there is no compilation. It doesn’t make much sense for an attribute to accept a Single-dimensional arrays of the above types. being that generates the compilation error described in the question. But finally, I will look for another way

  • He accepts the array, not a variable that is a array. When he puts the literal, he can compile and put in Metadata the data, when using a variable that will be initialized, would need to put the code unless it is something that does not need code to initialize, which is not the case of array, he has to wear a new and call a builder. He can no longer guarantee that this really is constant.

1


Solution

Since one attribute accepts a Type as a parameter (provided that it Type is derived from the expression typeof), you can use the "creativity".

So you need the attribute receive a string array as parameter but do not want to inform this array each time you decorate a member with this attribute, so that you want to get this array from a statement elsewhere, this statement you can change in the future or in one or another specific use of your attribute.

In order to have different array statements 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 parameter attribute 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 thus:

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

In the implementation of its attribute, you can create an instance of Type 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 seasickness. See for example that the attribute would accept any Type but wishing to receive only one Type specific (in case, the interface), and this is bad code.

Has a reason to Attributes accept a limited range of types as a parameter, and the reason is that a attribute is a declaration of a metadata.

I repeat: statement. Decorate a limb with a attribute adds metadata to it that should be immediately understood by the programmer without having to resort to other points in the code.

That is, the ideal (expressive) way to pass parameters to a attribute is a literal value or the expression of a literal value, such as a constant or a 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 intended to be "variables". They are helping to declare, expressively, the class metadata.

1

Alternative solution: Enumeration

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

Thus, the passage

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

will allow compilation.

If necessary, extract the name of the listed item as string, utilize Enum.GetName().

1

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

Considering the attribute

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

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

You can create a new Inherit it and pass the values you want

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

So using this new attribute any code that looks for a Customattribute type attribute should find this new one that has been created

[CustomAB()]
public void Metodo(){ ... }

Browser other questions tagged

You are not signed in. Login or sign up in order to post.