C# Question. Arbitrary class Class has method Foo(), a method which can throw an exception. Is there some way to add a private callback mechanism bar() to Class, such that if Foo() throws an exception, bar() execution will be triggered before the throw keeps going up the chain? If that can't happen, what about after the exception is caught?
-- Edit --
Since some of the initial comments are "this is confusing what are you doing dude" I'll address it further.
The reason I would like an exception listener is because I have some publicly readable boolean state about class Class, which I want to be set to true whenever an exception has been thrown. Since there could be potentially multiple functions within Class which throw exceptions, I don't want to do the boiler plate work of setting hasError to true each time an exception is thrown. Automate, baby.
So our interface, and main function are:
public interface IObjectProvider
{
IEnumerable<object> Allobjects { get; }
}
public interface IContext
{
delegate bool ContextIsStillValid(object o);
delegate void Run(object o);
}
// main program
public static void Main() {
IContext context = initcontext(...);
IObjectProvider objectProvider = initobjectprovider(...);
// ...program executes for awhile...
foreach(var obj in objectProvider.AllObjects)
{
if(context.ContextIsStillValid(obj))
{
try
{
context.Run(obj);
}
catch(Exception e)
{
// log the error
}
}
}
}
In the above code snippet, we specify some IContext which will 'Run' using some object, if and only if that IContext first successfully passes a 'Validation' check using that same object. Fine. Now, a common variation of implementation for IContext is the following (take my word, it is):
public class Class : IContext {
private bool _hasError = false;
// so our validation check is implemented with an internal flag.
// how is it set?
public bool ContextIsStillValid = (o) => !_hasError;
public void Run =
(o) =>
{
string potentially_null_string = getstring(...);
if(potentially_null_string == null)
{
// our internal flag is set upon the need to throw an exception
this._hasError = true;
throw new Exception("string was null at wrong time");
}
Global.DoSomethingWith(potentially_null_string.Split(',');
};
}
Here, we've demonstrated a common implementation of IContext, such that once the Run method throws a single Exception, the Run method should become unreachable due to IsContextStillValid subsequently always returning false.
Now imagine that there are other Exception-throwing calls within our implementation of Run(object). The problem is that every time we want to throw a new exception, we have to duplicate code to the effect of _hasError = true; throw new Exception(...);. Ideally, an exception listener would resolve this issue for us, and I am curious if any of you know how to implement one.
Hope that helps.
public class MyClass
{
public void Foo()
{
try
{
//Execute some code that might fail
}
catch
{
bar();
throw;
}
}
private void bar()
{
//do something before throwing
}
}
Related
When combining a using statement with a fluent api that can potentially throw, the lowered code will never call dispose correctly.
If I have the following class that exposes a fluent interface:
public class Wrapper : IDisposable
{
private bool _isAdded;
public Wrapper Add()
{
_isAdded = true;
return this;
}
public void Dispose() => Console.WriteLine("dispose called");
public Wrapper ThrowIfAdded() => _isAdded ? throw new Exception() : this;
}
and I call it with the following:
using var willNotDispose = new Wrapper().Add().ThrowIfAdded();
the lowered code will result in the Dispose call occurring after the fluent method chain is completed.
Wrapper willNotDispose = new Wrapper().Add().ThrowIfAdded();
try
{
}
finally
{
if (willNotDispose != null)
{
((IDisposable)willNotDispose).Dispose();
}
}
Alternatively, if the call to .ThrowIfAdded() is done outside of the initial using declaration,
using var willDispose = new Wrapper().Add();
willDispose.ThrowIfAdded();
the lowered code is generated as expected.
Wrapper willDispose = new Wrapper().Add();
try
{
willDispose.ThrowIfAdded();
}
finally
{
if (willDispose != null)
{
((IDisposable)willDispose).Dispose();
}
}
While I understand why this is occurring, it isn't desirable. Is there any way to coerce the former initialization to compile to the latter? Ideally, it would be an attribute or form of compiler hint that would result in:
Wrapper willDispose = default;
try
{
willDispose = new Wrapper().Add().ThrowIfAdded();
}
finally
{
if (willDispose != null)
{
((IDisposable)willDispose).Dispose();
}
}
which I would have expected the original example to compile to in the first place.
As pointed out in the comments, there is pre-existing guidance that when an exception is thrown in a constructor, it should be explicitly handled and the resources cleaned up.
This extends to CA2000 analysis that states:
When constructors that are protected by only one exception handler are
nested in the acquisition part of a using statement, a failure in the
outer constructor can result in the object created by the nested
constructor never being closed. In the following example, a failure in
the StreamReader constructor can result in the FileStream object never
being closed. CA2000 flags a violation of the rule in this case.
using (StreamReader sr = new StreamReader(new FileStream("C:/myfile.txt", FileMode.Create)))
{ ... }
While a Fluent API throwing an exception is not explicitly either a constructor or nested constructor throwing an exception, it should be treated the same since the object will be created and mutated outside of the try/finally block.
As a result, any method that can throw must first call dispose before allowing the exception to propagate.
public class Wrapper : IDisposable
{
private bool _isDisposed;
private bool _isAdded;
public Wrapper Add()
{
_isAdded = true;
return this;
}
public void Dispose()
{
if (_isDisposed)
{
return;
}
_isDisposed = true;
Console.WriteLine("dispose called");
}
public Wrapper ThrowIfAdded()
{
if (_isAdded)
{
Dispose();
throw new Exception();
}
return this;
}
}
This correctly assures that in cases where .Added() is called, .ThrowIfAdded() will dispose prior to throwing.
If .Added() is not called, the instance will be disposed at the end of the block as expected.
I have a C# application that can load other dlls with Activator.CreateInstance(type), that implement a given interface (plugins).
Now I want to catch all exceptions thrown from that new instance in it's own exception handler (because I cannot be sure that every exception is handled by the plugin properly) to present a message like:
Plugin [PluginName] caused the following error: [Exception.Message]
I can subscribe to the AppDomain.CurrentDomain.UnhandledException event, but this catches all exceptions and not only the ones caused by a certain plugin and I also can't see [that the|what] plugin caused the exception.
Is it possible to assign a exception handler to the created instance?
Thanks in advance,
Frank
I'm not sure I understand your exact scenario, but a solution could be creating a wrapper class around the plugin object that takes care of making sure all potential exceptions are handled correctly:
public interface IPluginObject
{
void Foo();
IBlah Bar();
...
}
public Wrapper<T>: IPluginObject where T: IPluginObject
{
private readonly T inner;
public Wrapper(IPlugin obj) { inner = obj; }
public void Foo()
{
try { inner.Foo() }
catch ....
finally ...
}
public IBlah Bar()
{
try { return inner.Bar(); }
catch ...
finally ...
}
}
Cumbersome? Yes, but you do get the benefit of knowing exactly what plugin is being troublesome.
Here's is my program
class Program
{
static void Main(string[] args)
{
throw new UserAlreadyLoggedInException("Hello");
}
}
public class UserAlreadyLoggedInException : Exception
{
public UserAlreadyLoggedInException(string message) : base(message)
{
Console.WriteLine("Here");
}
}
Now, I know that base class constructor runs before derived class constructor. But when I run the above code the output comes out to be
Here
Unhandled Exception:Testing.UserAlreadyLoggedInException:Hello.
How come "Here" is printed before Unhandled.....?
You first have to create the exception, before you can be thrown.
Creation of the exception instance initiated by new UserAlreadyLoggedInException;
UserAlreadyLoggedInException constructor called;
Call to Console.WriteLine inside constructor;
Constructor done;
Throwing of the newly created exception instance;
The exception isn't handled, thus the application error handler writes the error to the console.
Why don't you try this:
static class Program
{
static void Main()
{
throw new UserAlreadyLoggedInException("Hello");
}
}
class LoginException : Exception
{
public LoginException(string message) : base(message)
{
Console.WriteLine("least derived class");
}
}
class UserAlreadyLoggedInException : LoginException
{
public UserAlreadyLoggedInException(string message) : base(message)
{
Console.WriteLine("most derived class");
}
}
You can also try writing your Main method like this:
static void Main()
{
var ualie = new UserAlreadyLoggedInException("Hello");
Console.WriteLine("nothing bad has happened yet; nothing thrown yet");
throw ualie;
}
So constructing an Exception instance with the new keyword does not "raise" or "throw" an exception. You need throw for that. The throw statement works by first evaluating the expression that comes after the throw keyword. The result of that evaluation will be a reference to an exception instance. After evaluating the expression, throw "throws" the exception referred by the value of the expression.
Your misunderstanding is that the Exception "explodes" as soon as the instance constructor to System.Exception runs. That is not the case.
If you add a try/catch of your own the program flow becomes more apparent. Note that Exception's constructor does not write anything it just stores the message string for later use.
class Program
{
static void Main(string[] args)
{
try
{
throw new UserAlreadyLoggedInException("Hello");
}
catch (Exception e)
{
Console.WriteLine("My handled exception: {0}", e.Message);
}
}
}
public class UserAlreadyLoggedInException : Exception
{
public UserAlreadyLoggedInException(string message) : base(message)
{
Console.WriteLine("Here");
}
}
The exception is printed to the console after it has been instantiated and thrown.
The instantiation prints "Here", then the runtime catches it and prints the "Unhandled Exception:" ToString() representation.
Im trying to hunt down a race condition, and I come across a lot of suspecious functions. Most of them are not allowed to be called from two threads at the same time, but its hard to make sure they don't.
Is there some keyword to instruct the runtime to throw an exception as soon as a function is executing in parallel? I know I sometimes get an exception when another thread modifies a collection which im enumerating, but are safeguards like that enough to rely on?
The runtime can halt execution using the lock instruction, so all I need is a lock which throws an error.
You can use Monitor.TryEnter for this:
bool entered = !Monitor.TryEnter(someLockObject);
try
{
if (!entered)
throw Exception("Multi-thread call!");
// Actual code
}
finally
{
if (entered)
{
Monitor.Exit(someLockObject);
}
}
And it would be good to wrap that code in its own class:
public sealed class MultiThreadProtector : IDisposable
{
private object syncRoot;
public MultiThreadProtector(object syncRoot)
{
this.syncRoot = syncRoot;
if (!Monitor.TryEnter(syncRoot))
{
throw new Exception("Failure!");
}
}
public void Dispose()
{
Monitor.Exit(this.syncRoot);
}
}
This way you can execute it as follows:
using (new MultiThreadProtector(someLockObject))
{
// protected code.
}
I am writing tests to test Infopath Forms to open in Form Control, my test method is as
[TestMethod]
public void Validate_OpenInfopathInFormControl()
{
Helper.OpenForm();
//Other Code
}
I have written Helper class as
public class Helper
{
public static void OpenForm()
{
//Code to Open Form
}
}
But everytime I execute this code, this gives me:
Test method
InfoPathTest.TestAPI.Validate_OpenInfopathInFormControl
threw exception:
System.TypeInitializationException:
The type initializer for
'InfoPathTest.Helpers.Helper' threw an
exception. --->
System.NullReferenceException: Object
reference not set to an instance of an
object..
When I try to debug, it fails when Helper class needs to be initialized. This is really eating my head, is there any solution for this?
Here is the complete helper class:
namespace InfoPathTest.Helpers
{
public class Helper
{
//This is the form i need to OPEN
private static MainForm f = new MainForm();
private static bool _isOpen = false;
public static bool isOpen
{
set { _isOpen = value; }
get { return _isOpen; }
}
public static void OpenForm()
{
try
{
f.Show();
}
catch (Exception ex)
{
throw ex;
}
_isOpen = true;
}
public static void CloseForm()
{
f.Hide();
}
}
}
Your test calls Helper.OpenForm() and as you have no static constructor, the only thing I can see that would cause the exception to be thrown is:
private static MainForm f = new MainForm();
Therefore something in the constructor for MainForm is likely throwing an exception. Put a breakpoint on the first line of the constructor for MainForm and step through until you see where the exception is thrown.
Alternatively you might find it easier to determine what the problem is, at least initially, by writing a new test you can step through that calls new MainForm() directly:
[TestMethod]
public void Validate_OpenInfopathInFormControl()
{
var form = new MainForm();
}
Put a breakpoint on the only line of the test and step into the constructor to determine why it's throwing a NullReferenceException.
The type initialiser, in this case, is where your static fields are initialised; That is, these two lines:
private static MainForm f = new MainForm();
private static bool _isOpen = false;
The initialisation of a bool isn't going to cause any kind of exception, so it's highly likely that the source of the error is in the MainForm constructor.
Does the TypeInitializationException object contain any inner exceptions? If so, they should give you more info about the real cause of the error.
You have an error in your static constructor (they are called Type Initializers). The inner exception is a NullReference exception. If you post your code we might be able to help you.
The rules determine when type initializers get run are complex, but it is guaranteed that they are run before you access the type in any way. It might not be directly obvious to you that you have a type initializer on your Helper class because you might use implicit initialization:
public class Helper
{
static int i = 10; // This assignment will end up in a type initializer
static Helper()
{
// Explicit type initializer
// The compiler will make sure both, implicit and explicit initializations are run
}
}