Paul Michaels
Paul Michaels

Reputation: 16685

Properties exposing array elements in C#

I want to create a property in C# that sets or returns an individual member of an array. Currently, I have this:

private string[] myProperty;
public string MyProperty[int idx]
{
    get
    {
        if (myProperty == null)
            myProperty = new String[2];

        return myProperty[idx];
    }
    set
    {
        myProperty[idx] = value;
    }
}

However, I get the following compile error:

Bad array declarator: To declare a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type.

Upvotes: 13

Views: 17828

Answers (10)

abatishchev
abatishchev

Reputation: 100238

First, in-field declaration avoids excess check:

private string[] myProperty = new string[2];

You can implement several indexers via overloading by input type:

public string this[int index]
{
    get
    {
        return myProperty[index];
    }
    set
    {
        myProperty[index] = value;
    }
}

public object this[object a, object b] // different input type(s) (and different return type)
{
    get
    {
        // do other stuff
    }
}

Upvotes: 1

VladV
VladV

Reputation: 10349

C# provides no built-in mechanism to create indexed properties. You can use a class-level indexer (using this[int index] notation), but nothing like this on a property level.

One option is to create a helper class with an indexer and use this class as the property type. See an example on MSDN.

Upvotes: 1

user195488
user195488

Reputation:

You need to use an indexer. It works a little differently. See example:

public class Node
{
    public Node this[int offset]
    {
        get { return localList[offset]; }
    }
}

Note: You are allowed only one indexer per class. The reason is that it is too confusing to the compiler as to the meaning, so you only are allowed one.

You can also do this:

private static int[] _widget = new int[Counter];
public static int [] Widget
{
    get { return _widget; }
    set { _widget = value; }
}

...

for (int i = 0; i <  MyClass.Counter; i++)
{
    MyClass.Widget[i] = i;
}

...
double _newWidget5 = MyClass.Widget[5];
// and so on...

Upvotes: 0

Fredrik M&#246;rk
Fredrik M&#246;rk

Reputation: 158289

Exposing your array through a read-only property might cover your needs. Since you don't want to allow other code to assign the array as such, there is no need for a public setter:

private string[] myProperty;
public string[] MyProperty
{
    get
    {
        if (myProperty == null)
        {
            myProperty = new String[2];
        }

        return myProperty;
    }  
}

Then you can write code as such:

theObject.MyProperty[1] = "some string";

...but you cannot replace the array itself:

theObject.MyProperty = new string[2]; // will not compile

Upvotes: 2

Tokk
Tokk

Reputation: 4502

You can use it this way:

    private string[] myProp;
    public string[] MyProp
    {
        get
        {
            if (myProp == null)
            {
                myProp = new String[2];
            }
            return myProp;
        }

        set
        {
            myProp = value;
        }
    }

And it's possible to acces myProp[1] as MyProp[1] for Example

Upvotes: 2

fletcher
fletcher

Reputation: 13740

You could do something like this:

class Indexers
{
    private string[] _strings = new [] {"A","B"};
    private int[] _ints = new[] { 1, 2 };

    public string[] Strings
    {
        get{ return _strings;}
    }

    public int[] Ints
    {
        get{ return _ints;}
    }
}

class Program
{
    static void Main(string[] args)
    {
        Indexers indexers = new Indexers();

        int a1 = indexers.Ints[0];
        string a2 = indexers.Strings[0];
    }
}

Upvotes: 1

Dan Tao
Dan Tao

Reputation: 128317

How about this: write a class that does one thing and one thing only: provide random access to elements of some underlying indexed collection. Give this class a this indexer.

For properties that you want to provide random access to, simply return an instance of this indexer class.

Trivial implementation:

public class Indexer<T>
{
    private IList<T> _source;

    public Indexer(IList<T> source)
    {
        _source = source;
    }

    public T this[int index]
    {
        get { return _source[index]; }
        set { _source[index] = value; }
    }
}

public static class IndexHelper
{
    public static Indexer<T> GetIndexer<T>(this IList<T> indexedCollection)
    {
        // could cache this result for a performance improvement,
        // if appropriate
        return new Indexer<T>(indexedCollection);
    }
}

Refactoring into your code:

private string[] myProperty;
public Indexer<string> MyProperty
{
    get
    {
        return myProperty.GetIndexer();
    }
}

This will allow you to have as many indexed properties as you want, without needing to expose those properties with the IList<T> interface.

Upvotes: 15

Russ
Russ

Reputation: 4163

An option is to recode it as follows:

private string[] myProperty = new string[2]; 
public string[] MyProperty
{ 
    get 
    { 
        return myProperty;
    } 
    set 
    { 
        myProperty = value; 
    } 
} 

It'll compile, but it does have its own set of issues (fxCop will yell about it, but it can lead you to other options).

Upvotes: 1

joekoyote
joekoyote

Reputation: 221

C# allows only one indexed property per class, so you are forced to use this.

Upvotes: 5

leppie
leppie

Reputation: 117220

You must use this as the property name for indexers.

Upvotes: 5

Related Questions