Hello World: the ‘new’ keyword

Everyone knows what the new keyword is for in C# – you use it to call constructor of an object, right? What can be simpler? Actually, that’s true, but not the whole truth. That’s the most common way to use it. However, new is one of contextual keywords, which means, it can have different meaning, depending on the context where it’s being used.

The new keyword can be used in three scenarios:

  • the one presented above, everyone immediately thinks of – creating objects.
  • as modifier, to hide members of a base class.
  • as generic constraint.

Creating objects is pretty straightforward, and there’s no magic there:

string[] stringArray = new string[] { "kot", "knur", "pies" };  //creating array

List<string> stringList = new List<string>(stringArray);        //creating class

DateTime dateTime = new DateTime(2000, 1, 1);                   //creating struct

Action myDelegate = new Action(delegate { });                   //creating delegate

var myAnonymousType = new { A = 1, Name = "My name" };          //creating anonymous type

The only thing that may look unfamiliar, is new C# 3.0 anonymous types initializing. It works in similar way to anonymous delegates. Here I created a nameless class, that two fields: A (of type int) and Name (of type string). This is the most basic stuff.

Not everyone however, knows about two other usages of that keyword. Let’s consider very simple example:

class Program

{

    static void Main(string[] args)

    {

        InheritedClass inherited = new InheritedClass();

        inherited.Write();

        UseBaseWrite(inherited);

    }

 

    public static void UseBaseWrite(BaseClass item)

    { item.Write(); }

}

 

public class BaseClass

{

    public void Write()

    { Console.WriteLine("Hello. I'm a BaseClass' Write!"); }

}

 

public class InheritedClass : BaseClass

{

    public new void Write()

    { Console.WriteLine("Hello. I'm a InheritedClass' Write!"); }

}

We have two classes, BaseClass, and InheritedClass that inherits from BaseClass. They both have non-virtual method Write, that writes a string to the console, and inherited class has a new keywords as its modifier (the code would actually work the same without that keyword, we would however receive compile time warning). We then create InheritedClass’ instance, and pass it to UseBaseWrite, method, that calls its Write method.

So what would be the outcome of that program?

Hello. I’m a InheritedClass’ Write!

Hello. I’m a BaseClass’ Write!

 

If you bet on that answer you can give yourself a reward. Now the question for those of you who guessed differently is – why? Notice that Write in BaseClass is not virtual, and as such we’re not overriding it in InheritedClass. We just create brand new method, that has no connection whatsoever to BaseClass’ Write, except the fact that it has the same name. This way,(as InheritedClass inherits from BaseClass) we have in it two unrelated methods with the same name. And here comes the tricky part: Which one of those two methods will be called, depends on the type of reference you’re holding to your object. If you reference it as InheritedClass (as we did in 6th line), we call Write implemented in InheritedClass. When we however reference the same object as BaseClass (as we did in 10th line) BaseClass’s implementation gets called. That’s why new is not inheritance modifier, but it let’s you have method in inherited class with the same name as base class, you don’t get however polymorphic  behavior. In this context it’s usability is really limited.

More interesting usage is new as generic constraint:

static void Main(string[] args)

{

    GenericClass<DateTime> d = new GenericClass<DateTime>();//ok

    DateTime dateTime = d.GetNewItem();

    GenericClass<string> s = new GenericClass<string>();//compile error

}

 

public class GenericClass<T> where T : new()

{

    public T GetNewItem()

    {

        return new T();

    }

}

When you specify new() on constraints list for your generic type, you demand, that generic type T has to have public parameterles constructor.

In the example above, it’s ok to pass DateTime as generic parameter, as it meets the constraint. String however does not have default constructor, that’s why this code would fail to compile.

It let’s you then call new T() anywhere in your code. It can be very useful sometimes. One more thing to keep in mind, is that when you specify more than one generic constraint, new() must be the last one of them.

//compilation error

public class GenericClass<T> where T :  new(), IEnumerable

{ public T GetNewItem() { return new T(); } }

 

//now ok

public class GenericClass<T> where T : IEnumerable, new()

{ public T GetNewItem() { return new T(); } }

And that’s basically all. I hope it was informative and I didn’t miss anything. Happy coding.

Technorati Tags: , , ,