3

Consider the following issue

When designing a framework, an interface exposing some event is presented

interface I
{
  event MyEventHandler MyEvent
}

This interface will eventually be implemented by many different 3rd party vendors, and may be consumed by various clients.

Since each vendor may new up the event args with invalid data, the only control I have as a framework author is at the event args level, so I thought of the following pattern:

class MyEventArgs
{

 public int? MyProperty{get;}

 MyEventArgs(int arg)
 {

   if(arg.IsInvalidArgument())//Let's pretend that there's such an extension method
     throw new ArgumentException(...)

   MyProperty = arg;
 }

This ensures that a client can not use invalid values provided by some rogue piece of code, since the constructor throws an exception, hence the integer will have no value assigned, making it a null reference.

However, this also creates overhead in client code, since now the client has to check the HasValue and then access Value, making the EventArgument less user friendly.. This becomes even more cumbersome when the amount of parameters per event argument grow.

I could technically remove the question mark, which would rid the client of the Nullable nonsense, since in my opinion there is no way on god's green earth to obtain a reference to such an instance, but the problem is that this scenario, although easy to test, may have edge cases which I never thought of, hence my question.

Is there any possible way to obtain a reference to an instance whose constructor had thrown an exception and pass it to the event listeners?

Eyal Perry
  • 2,255
  • 18
  • 26
  • It's really unclear to me what you're trying to ask. First of all, what "overhead" are you talking about? Second, what "reference" do you want to obtain exactly? – CodeCaster Jun 25 '16 at 08:35
  • @CodeCaster I have edited my question. Thanks for bringing the unclarity to my attention.. the overhead is in using the Nullable API for each property in the event argument class, the reference is a reference whose constructor had thrown an exception. – Eyal Perry Jun 25 '16 at 08:39

3 Answers3

3

When a constructor throws an exception there is no way to obtain a reference to that object (except if the object cooperates by handing out this before throwing; not likely, bad design).

For that reason your invalidly valued object is unreachable. It's state is indeed invalid (default initialized) but nobody can see it. It's like a virtual machine that is corrupted on the inside and tries to launch missiles but you have disabled the virtual NIC.

This pattern is used all over the place. You have used it many times without realizing. For example, if you say new FileStream(null) how would you obtain a reference to that invalid stream? You can't.

Just do the normal thing. It's good that you thought this through, though.

Is there any possible way to obtain a reference to an instance whose constructor had thrown an exception and pass it to the event listeners?

No. But here's an example where it's possible:

class C {
 public static C Instance; 
 public C() {
  Instance = this; //publish/leak
  throw ...;
 }
}

Just don't do that. This is unnatural code anyway. The constructor of an object normally should not do much, it should bring the object into a valid state and not cause side-effects. Side-effects are the only way to publish a reference to this.

There's one more catch: A finalizer will be invoked on that object if one is present. Finalizers are rare because because most of the time unmanaged resources should be held by handle classes. For that reason this issue rarely comes into effect. But a finalizer can see the private state of its object. Make sure that it can deal with that. FileStreams finalizer will probably check for aborted initialization and do nothing.

usr
  • 168,620
  • 35
  • 240
  • 369
0

To answer your question. No. you can't have a null result if an error is encountered in a constructor

However I think the best possible way around this is to add a static constructing function to the MyEventArgs class

public static int DEFAULT_ARG = 1;//you can set this to whatever you want
public static Create(int arg)
{
    if(checkArg(arg))
    {
        return new MyEventArgs(arg);
    }
    return new MyEventArgs(MyEventArgs.DEFAULT_ARG);
}

Then instead of using the constructor directory using var event = new MyEventArgs(arg); you use var event = MyEventArgs.Create(arg);

It's a bit of a stress using this method on multiple eventargs but hey :) you could always derive all of them from the same generic abstract class

Hope this helps :)

  • Thanks for the correction, however I do not see how this helps me? What I am trying to establish is whether the instance can be obtained which will enable invalid event argument instances to bubble up to client code despite the safety mechanism.. – Eyal Perry Jun 25 '16 at 08:33
  • Yes the solution will be to return new MyEventArgs(MyEventArgs.DEFAULT_ARG) instead of null – Efe Omoregie Elijah Jun 25 '16 at 08:37
  • This is indeed a solution, of sorts, however I would like to avoid it since this would require every event argument to have such a function. Also, my question does not require a solution, but more of an answer in the form of yes / no and why. I do thank you for the effort. – Eyal Perry Jun 25 '16 at 08:41
  • I'm happy to help. The thing is that returning a null value from a constructor is impossible. This is the workaround i recommend – Efe Omoregie Elijah Jun 25 '16 at 10:05
0

the client has to check the HasValue and then access Value

Well it's not necessary to make the property a Nullable<int>, as you can only set it from the constructor (assuming an omitted private set), where it is non-nullable.

Is there any possible way to obtain a reference to an instance whose constructor had thrown an exception

No, when a constructor throws an exception, you don't get an instance back.

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • It is necessary, so that properties are not initialized with default values, such as zero which might be valid in the property's domain. Which is why I put it there in the first place.. As for the "you don't get an instance back" part.. do you have something concrete to back this up? I tend to believe this to, but I have yet to find a concrete answer. – Eyal Perry Jun 25 '16 at 08:45
  • 1
    @Eyal http://stackoverflow.com/questions/10119896/why-throwing-exception-in-constructor-results-in-a-null-reference. I can't say anything about the nullable design at the moment. – CodeCaster Jun 25 '16 at 09:31
  • @CodeCaster Thanks. – Eyal Perry Jun 25 '16 at 10:13