Jo Smo
Jo Smo

Reputation: 7169

How to set a property of a class to be returned by default for an object/class?

I'm trying to implement my own list class. Just for training, to better understand how things work.

I have something like:

public class TestClass {
    public int[] List;
    // Add(), ...
}

I want to be able to retrieve the array (which is the property of TestClass) like this:

var testClass = new TestClass();
int[] list = testClass; // without the ".List" list would point to the array

and not like this:

var testClass = new TestClass();
int[] list = testClass.List;

The same way that the c# build-in generic list class can be used.

How can i achieve this (if this is even possible)?

UPDATE

I changed the "list" to int[], i hope this will help.

I know that i could just do something like:

int[] list = new int[10];

But i needed the TestClass because i needed some other (extended) properties about the array and more custom methods for it.

UPDATE 2

Maybe this will clear things up some more.

I'm trying to find out, how the generic List<T> class works in this case:

var list = new List<T>();
foreach(var oneElement in list)

In my case i have to do it like this:

var list = new TestClass();
foreach(var oneElement in list.List)

I want to be able to retrieve my array the same way as the .NET or C# List<T> class retrieves it's "underlying array".

Upvotes: 1

Views: 83

Answers (4)

Mike Zboray
Mike Zboray

Reputation: 40808

To use your class in a foreach statement, you should implement IEnumerable<T>. This is fairly straight-forward:

public class TestClass : IEnumerable<int>
{
    private static readonly int[] Empty = new int[0];

    public int[] List;

    public IEnumerator<int> GetEnumerator() 
    {
        int[] array = List == null ? Empty : List;
        return array.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerator.GetEnumerator()
    {
        return GetEnumerator();
    }
}

I added a simple null check in case List never gets assigned it will not throw when enumerating.

This allows you to use it in a foreach statement, as well as use LINQ extension methods:

var list = new TestClass();
foreach(var oneElement in list)
{
}

If you want other list like features you should probably implement IList<T>. Also there is a base class, System.Collections.ObjectModel.Collection<T> that implements all that for you. It has overridable methods so you can update other state in your class when items are added or removed. List<T> has no overridable methods so its uses as a base class are limited.

Upvotes: 1

D Stanley
D Stanley

Reputation: 152501

DISCLAIMER

I add this only because the OP asked for it, but I don't think it's the appropriate solution in this (or most any other) situation.


I want to be able to get the list like this:

var testClass = new TestClass();
var list = testClass;

Well one problem is that you're using var. The compiler will use the most reasonable type for list, which is TestClass, since that's what the type of testClass is.

You could add a implicit casting operator if you wanted list to be of a list type

public class TestClass<T> {
    public T[] List ;
    // ...

    public static implicit operator List<T>(TestClass<T> t)
    {
       return t.List.ToList();
    }
}

but then you'll have to specify the type of list so that the compiler knows to cast the object:

var testClass = new TestClass<int>();
testClass.List = new[] {1,2,3,4};
List<int> list = testClass; // can't use `var here AND cast to List<T>

Also note that the "list" is read-only. You're retrieving a copy of the internal list. I suspect that you instead want to implement the interfaces (and all methods) methods that List<T> implements rather then just exposing the underlying collection as a copy.

Upvotes: 0

Hutch
Hutch

Reputation: 1007

It sounds like you might want to create an indexer. You can do so as follows:

public class TestClass
{
    public object this[int i]
    {
        get
        {
            // put your code here to return object i from the list
        }
        set
        {
            // put your code here to set object i in the list.
            // A variable named "value" contains the incoming value.
        }
    }
}

You can now access items in the list as follows:

var testClass = new TestClass();
testClass[0] = 100; // any object really
var item = testClass[0];

You might also want to look at generic classes, which are useful when creating custom containers.

Upvotes: -1

Dmitry
Dmitry

Reputation: 14059

If var list is allowed to have one of the types IEnumerable<T>, ICollection<T> or IList<T>, then you just need to implement one of the interfaces IEnumerable<T>, ICollection<T> or IList<T>:

public class TestClass : IList<SomeTypeOrGenericT>
{
    public SomeTypeOrGenericT[] List;
    // ...

    // members of IList<SomeTypeOrGenericT>
}

Upvotes: 3

Related Questions