7

What I need is to check the parameters passed to the constructor and prevent the instantiation of the specific object in case they are treated as invalid.

What I have found is that an exception can be thrown so the object reference will end up with "null" as expected.

For example, this class will be instantiated only if the integer passed to the constructor is non negative.

class MyClass
{
    public MyClass(int a)
    {
        if (a < 0)
        {
            throw new Exception();
        }
    }
}

Although the above works fine, I bet that c# can provide a cleaner way to do this, avoiding the extra cost of the try/catch need, each time a new object is about to be constructed.

static void Main(string[] args)
{
    MyClass e1;
    MyClass e2;

    try
    {
        e1 = new MyClass(1);
    } 
    catch(Exception)   { }

    try
    {
        e2 = new MyClass(-1);
    } 
    catch(Exception) { }
}
thanos.a
  • 2,246
  • 3
  • 33
  • 29
  • 1
    what do you want to do if user pass invalid value to the constructor ? – Selman Genç Jan 23 '14 at 00:15
  • I need to end up with no object which means "null" reference. In my example the e2 should end up with null value. – thanos.a Jan 23 '14 at 00:16
  • 2
    You should implement factory pattern and make the check in factory method instead of constructor. And throwing an exception from constructor is the only way to interrupt instance creation. – MarcinJuraszek Jan 23 '14 at 00:17
  • 1
    @MarcinJuraszek: it would be weird if a factory knows more about a class constraints than the class itself – zerkms Jan 23 '14 at 00:19
  • 1
    @zerkms You can expose internal static method from class and use it from factory methods. Or make factory method part of the class itself. – MarcinJuraszek Jan 23 '14 at 00:20
  • Guys, why do you state "you **should** consider using the Factory Pattern" without further explanation? Why the current OP's solution is bad? Why would one prefer the factory method pattern over what OP currently has? Any real application design perspective reasons? – zerkms Jan 23 '14 at 00:24
  • 1
    FYI: In .NET, class names typically begin with a capital letter. (You'll notice the code highlighting works better too.) – Jonathon Reinhart Jan 23 '14 at 00:36

3 Answers3

15

In cases like this, you should consider using the Factory Pattern. You made the constructor private, and instead use a static method to return an instance.

public class Foo {
    private Foo(int a) { ... }

    public static Foo GetFoo(int a) {
        if (a < 0) {
            throw new Exception("No Foo for you!");

            // or

            return null;
        }

        return new Foo(a);
    }
}

public class Program {
    public static void Main() {
        Foo f;

        f = new Foo();        // Not allowed, ctor is private.

        f = Foo.GetFoo(42);   // Do this instead.
    }
}

With this, you can do some pretty interesting stuff.

Here, we have a Foo class, with different sub-classes. By using the Factory Pattern, we can construct an instance of a particular Foo sub-class, without the outside world even knowing that any subclasses exist!

public abstract class Foo { 

    // Private implementations of Foo
    // No one outside can ever construct one directly.
    private class RedFoo : Foo { }
    private class GreenFoo : Foo { }
    private class BlueFoo : Foo { }

    public static Foo GetColoredFoo(string color) {

        switch (color.ToLower()) {
        case "red":    return new RedFoo();
        case "green":  return new GreenFoo();
        case "blue":   return new BlueFoo();
        }

        throw new Exception("No Foo for that color!");
    }
}

public class Program {
    public static void Main() {
        Foo f;

        f = new Foo();     // Not allowed; Foo is abstract

        f = new RedFoo();  // Not allowed, RedFoo is private, inside of Foo

        f = Foo.GetColoredFoo("red");  // Returns an instance of RedFoo

    }
}

This moves the knowledge of "how to best construct the object you really need" into the definition of the class itself, and of course eliminates the try/catch. You could apply any logic you need inside of the static factory method.

Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
  • Upvoted, better example than my answer. Although may consider returning null over throwing an exception - as that was his original goal. – Nabren Jan 23 '14 at 00:21
  • 3
    This doesn't solve the question of 'avoiding the extra cost of the try/catch needed, each time a new object is about to be constructed'. Exception still gets thrown. – TheDude Jan 23 '14 at 00:26
  • @TheDude I added a second example to show the true power of the Factory Pattern. – Jonathon Reinhart Jan 23 '14 at 00:29
  • @TheDude I made an edit in the first example to show how he could return `null`, which would provide the same effect as his `try`/`catch` code. – Jonathon Reinhart Jan 23 '14 at 01:28
4

You can go with the factory pattern, as suggested by MarcinJruaszek, by making the constructor private and add a static method:

public class myClass
{
    private myClass(int a)
    {
        // constructor
    }

   public static myClass Create(int a){
       if (a < 0)
        {
            return null;
        }
        return new myClass(a);
   }
}

And do myClass.Create(1).

TheDude
  • 3,796
  • 2
  • 28
  • 51
  • +1. This is variant of "factory pattern"... not sure why there is "or this" in your post. – Alexei Levenkov Jan 23 '14 at 00:23
  • From my understanding, factory pattern uses a separate class as the factory. – TheDude Jan 23 '14 at 00:24
  • Edited my answer to reflect it! Thanks! – TheDude Jan 23 '14 at 00:27
  • 1
    To be precise it is [Factory method pattern](http://en.wikipedia.org/wiki/Factory_method_pattern), unlike something like [Abstract factory](http://en.wikipedia.org/wiki/Abstract_factory_pattern) which I guess more common meaning for "factory". – Alexei Levenkov Jan 23 '14 at 00:28
1

What I suggest you do is create a static method of your class that accepts the parameters you need to verify and have that return the object. I do not know of a way to abandon object creation during a constructor without throwing an Exception.

Nabren
  • 582
  • 1
  • 7
  • 17