niico
niico

Reputation: 12749

Explanation of left and right side of statement when creating new class instance

I have a class

public class Table
{
    public string color {get; set;}
    public string height {get; set;}
}

When I want to create a new instance of this class I use:

//1.
var myTable = new Table();

or

//2.
Table myTable = new Table();

or

//3.
IEnumerable<Table> Tables = new List<Table>();

but not

//4.
List<Table> y = new IEnumerable<Table>();

Can somebody explain what the left side (var / Table / IEnumerable) is doing and what the right side (new Table / new List() etc) in contrast is doing.

Why are they the same sometimes (eg 2) and different at other times (eg 3).

What's the difference between these three:

var Tables = new List<Table>();
List<Table> Tables = new List<Table>();
IEnumerable<Table> Tables = new List<Table>();

I know this is basic stuff, but I have not found a clear explanation of what the left and right-hand side of the statement means when creating an instance of a class in C# - online.

thx.

Upvotes: 2

Views: 1526

Answers (4)

infiniteRefactor
infiniteRefactor

Reputation: 2120

In short

Right hand side creates the actual object, left hand side creates a reference to the object.

Long version

Right hand side creates the actual object there is no mystery here I guess. You cannot do new IEnumerable<Table>() because IEnumerable is an interface, not a class. You can only create objects from classes.

Then you need to assign this object to a certain reference and declare the type of the reference.

List<Table> Tables = new List<Table>();

This is straightforward, your reference has the same type with your object.

IEnumerable<Table> Tables = new List<Table>();

This involves inheritance of classes. If you go to the source code of class List you will see List implement interface IEnumerable. Thus when defining references you can use implemented interface and extended classes instead of the real class name.

This has some additional benefits, such that you can assign objects from other classes that implement IEnumerable<Table> to Tables.

var Tables = new List<Table>();

This style has been around only recently. Basically if you do not bother to give any type to the reference, the compiler can deduce one for you. If you mouse over to var you'll see the inferred type. If you don't find the deduced type suitable, you can always write the type yourself.

Upvotes: 1

Crowcoder
Crowcoder

Reputation: 11514

As others have mentioned, not all IEnumerable<T>'s are List<T>'s. An relevant example will make it clear.

IEnumerable<int> ints = new int[5];
List<int> intsList = ints; //does not compile!

An array of ints is not the same as a List of ints even though they both implement IEnumerable. Even more obvious is the Dictionary. Clearly a Dictionary has different methods and properties than a List:

IEnumerable<KeyValuePair<string, string>> keyvals = new Dictionary<string,string>();
List<KeyValuePair<string,string>> keyvalList = keyvals; //does not compile!

You see, when you do this:

IEnumerable<KeyValuePair<string, string>> keyvals = new Dictionary<string,string>();

you lose Dictionary specific features. You cannot, for instance, do:

keyvals.ContainsKey("foo");

IEnumerable<KeyValuePair<string,string>> does not define a ContainsKey method. In fact, basically all IEnumerable<T> does is expose GetEnumerator() and some extension methods.

But IEnumerable<T> can still be very useful. Consider this LinqPad script that defines a generic method that receives an IEnumerable<Table>. You can send it an array of Table or a List of Table or a Stack of Table, etc., and it will still work:

void Main()
{
    IEnumerable<SomeTable> arrayOfSomeTable = 
        new SomeTable[] { new SomeTable(), new SomeTable() };

    IEnumerable<SomeTable> listOfSomeTable = 
        new List<SomeTable> { new SomeTable(), new SomeTable() };

    Stack<SomeOtherTable> stackOfOtherTable = new Stack<SomeOtherTable>();
    stackOfOtherTable.Push(new SomeOtherTable());
    stackOfOtherTable.Push(new SomeOtherTable());
    IEnumerable<SomeOtherTable> stackOtherTable = stackOfOtherTable;

    ShowTableDef(arrayOfSomeTable);
    ShowTableDef(listOfSomeTable);
    ShowTableDef(stackOfOtherTable);
}

public void ShowTableDef<T>(IEnumerable<T> objectToLog) where T : ITable
{
    foreach (ITable tbl in objectToLog)
    {
        Console.WriteLine(tbl.GetTableDefinition());
    }
}

public interface ITable { string GetTableDefinition(); }

public class SomeTable : ITable
{
    public string GetTableDefinition() { return "foo"; }
}

public class SomeOtherTable : ITable
{
    public string GetTableDefinition() { return "bar"; }
}

Upvotes: 0

Sweeper
Sweeper

Reputation: 273125

The left side specifies the type of the variable. Just like in int i;, the word int says that i is an integer. And var means that you are too lazy to write the type name and you want to compiler to guess the type you want to use.

That's the easy part.

The right side is a value that you assign to the variable. Just like in int i = 10;, 10 is stored in i, in

Table myTable = new Table();

the value of new Table() is stored in myTable.

And what does new Table() do? Well, it simply creates a new instance of Table.

This is easy as well.

In other words, all your are doing is creating a new instance of Table and putting it into a variable called myTable. It's just like:

int i = 1 + 1;

You create a new integer 2 by adding 1 to 1, then you assign the result to i.

why can the two sides be different?

Just like in int i = 1 + 1;, the right side doesn't need to be the same as the left side (and sometimes they must be different). Since all you're doing here is assigning a value to a variable, as long as the right side's value can be put into the variable on the left, it's fine!

Now here comes the hard part.

Why does this work?

IEnumerable<Table> Tables = new List<Table>();

Because an instance of List<Table> can be put into an instance of IEnumerable<Table>. It's that simple!

why can an instance of List<Table> be put into an instance of IEnumerable<Table>?

Because List<T> implements the interface IEnumerable<T>. Therefore, a List<T> has all the methods in IEnumerable<T>.

Why doesn't this work?

List<Table> y = new IEnumerable<Table>();

Because first, you cannot create an instance of an interface by new XXX(). You should learn more about how interfaces work in C#. Second, an object whose type is IEnumerable<T> is not compatible with List<T>.

Still don't understand why an object whose type is IEnumerable<T> is not compatible with List<T>?

You're basically doing this:

int i = 1.234;

double and int just don't go together!

Upvotes: 3

Max Hampton
Max Hampton

Reputation: 1304

In all cases you are instantiating your Table class. The most basic instantiation is case 2:

Table myTable = new Table();

You are essentially saying, give me an instance of the Table class called myTable to work with locally.

In case 1, where you use the var keyword, you are doing the same thing, except myTable is implicitly typed. The compiler decides what type myTable should be. It is still an instance of your Table class, and is still strongly typed.

List<T> implements the interface IEnumerable<T>. All List<T>'s are IEnumerable<T>'s, and can be instantiated as such, like you do in case 3. When instantiating this way, you do not have access to the methods specific to the IList<T> interface, and can only access methods of the IEnumerable<T> interface.

Case 4 will not work for at least a couple of reasons. First, you cannot instantiate an interface. Second, even if you could, not all IEnumerable<T>'s are List<T>'s. Read up on Inheritance and you'll start to understand this case.

Upvotes: 1

Related Questions