简体   繁体   中英

Handle an exception thrown from ctor with ImportingConstructor

Here below are two classes where one of them is importing another one using ImportingConstructor and throws an MyException right from ctor. So, I expect to catch MyException in another class, but I get quite another one, namely:

 System.InvalidOperationException: GetExportedValue cannot be called before prerequisite import 'Class1..ctor ' has been set. (...)

How can I force the MEF to throw an original exception, or at least to wrap original one to some exception, so I could to handle it from my code?

[Export]
class Class1
{
    public Class1()
    {
       (....)
       throw new MyException("MyException has been thrown");
    }
}

class Class2
{
    [ImportingConstructor]
    public Class2(Class1 class1)
    {
        (....)
    }
}

static void Main(string[] args)
{
    var catalog = new AggregateCatalog(
        new AssemblyCatalog(typeof (Class1).Assembly));
    CompositionContainer container = new CompositionContainer(catalog, true);
    try{
      Class2 class2 = container.GetExportedValue<Class2>();
    }
    catch(MyException ex){...}
}

AFAIK, you cannot get MEF to throw the original exception, but the original exception is within the stack trace if you dig. So one way to handle this would be to inspect the CompositionException for the exception you expected. If you find it, then you can continue with the error handling you need.

try
{
    Class2 class2 = container.GetExportedValue<Class2>();
}
catch (CompositionException ex)
{
    foreach (var cause in ex.RootCauses)
    {
        //Check if current cause is the Exception we're looking for
        var myError = cause as MyException;

        //If it's not, check the inner exception (chances are it'll be here)
        if (myError == null)
            myError = cause.InnerException as MyException;

        if (myError != null)
        {
            //do what you want
        }
    }
}

Depending on where the exception is thrown may depend on where you need to look in the stack trace, but the simple example above should get you down the right path. In case you're interested, here's the MSDN docs

For completeness, here's the full implementation

[Export]
class Class1
{
    public Class1()
    {
        throw new MyException("MyException has been thrown");
    }
}

[Export]
class Class2
{
    [ImportingConstructor]
    public Class2(Class1 class1)
    {

    }
}

static void Main(string[] args)
{
    var catalog = new AggregateCatalog(
        new AssemblyCatalog(typeof (Class1).Assembly));
    CompositionContainer container = new CompositionContainer(catalog, true);
    try
    {
        Class2 class2 = container.GetExportedValue<Class2>();
    }
    catch (CompositionException ex)
    {
        foreach (var cause in ex.RootCauses)
        {
            var myError = cause as MyException;

            if (myError == null)
                myError = cause.InnerException as MyException;

            if (myError != null)
            {
                //do what you want
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM