我有以下类示例:
public class ExceptionOne : BaseException
{
//Define the error bit the exception represents
public static int ErrorBitNumber = 1234;
public ExceptionOne()
{
//Do something in the ctor
}
}
(在BaseException
中没有相关的功能,所以没有必要显示代码;))
此外,还有其他异常类,其属性称为ErrorBitNumber
,但属性ErrorBitNumber
具有其他值。每个异常类代表一个errorbitnumber——所以总是有一个类对应一个errorbitnumber。
由于我永远不知道我收到了哪个errorbitnumber (如果我收到一个),我想实现以下->
- 遍历从
BaseException
派生的每个现有类并查找接收到的错误比特数 - 如果找到类,创建一个特定类的实例(填充一些进一步的属性或)
- 扔
我知道这应该可以通过使用反射来实现-但我真的不知道如何。此外,我认为使用ErrorBitNumber
作为public static
应该是正确的方法。如果没有,请随时纠正我。
用于理解:我们有将被解析的头文件。在这个头文件中定义了一些错误。对于每个错误,将创建一个带有特定errorbitnumber的异常类。因此,在架构的最低层,我接收到一个错误比特数并且必须抛出特定的异常它表示特定的errorbitnumber
假设所有相关的类都直接派生自BaseException
,并且与它在同一个程序集中,您可以使用以下代码:
var exceptionType =
typeof(BaseException)
.Assembly.GetTypes()
.Where(x => x.BaseType == typeof(BaseException))
.Select(x => new { ExceptionType = x, Property = x.GetProperty("ErrorBitNumber", BindingFlags.Public | BindingFlags.Static) })
.Where(x => x.Property != null)
.FirstOrDefault(x => x.Property.GetValue(null, null) == errorBitNumber)
.ExceptionType;
if(exceptionType == null)
throw new InvalidOperationException("No matching exception has been found");
var exception = (BaseException)Activator.CreateInstance(exceptionType);
throw exception;
这应该可以工作,但我永远不会使用它。我将创建某种异常注册表,可用于检索特定错误位的异常的新实例。
异常注册表可以通过多种方式实现,主要取决于您的确切需求。最通用和灵活的方法是简单地注册工厂:
public class ExceptionRegistry<TKey, TExceptionBase> where TExceptionBase : Exception
{
private readonly Dictionary<TKey, Func<TExceptionBase>> _factories = new ...;
public void Register(TKey key, Func<TExceptionBase> factory)
{
_factories[key] = factory;
}
public TExceptionBase GetInstance(TKey key)
{
Func<TExceptionBase> factory;
if(!_factories.TryGetValue(key, out factory))
throw new InvalidOperationException("No matching factory has been found");
return factory();
}
}
的用法如下:
var exception = registry.GetInstance(errorBitNumber);
throw exception;
因为它是最灵活的方法,但在实际注册异常类方面,它也是最冗长的方法:
var registry = new ExceptionRegistry<int, BaseException>();
registry.Register(ExceptionOne.ErrorBitNumber, () => new ExceptionOne());
registry.Register(ExceptionTwo.ErrorBitNumber, () => new ExceptionTwo());
registry.Register(ExceptionThree.ErrorBitNumber, () => new ExceptionThree());
基本上必须手动注册每个异常类。然而,这样做的好处是您可以自定义异常的创建:
registry.Register(ExceptionFour.ErrorBitNumber,
() => new ExceptionFour(some, parameters));
如果您不想为每个异常类创建手动注册,您可以将这两种方法结合使用:
您仍然可以使用反射来获取所有异常类。但是结果将用于填充注册中心,以便您可以使用注册中心实际检索实例。以这种方式使用反射来创建注册表基本上是"约定优于配置"。这里的最大优点是您只需执行一次注册,基本上就变成了基础架构代码。在那之后,你就有了一个定义良好的接口——注册表——你可以使用。
可以是这样的:
var registry = new ExceptionRegistry<int, BaseException>();
var exceptions =
typeof(BaseException)
.Assembly.GetTypes()
.Where(x => x.BaseType == typeof(BaseException))
.Select(x => new { ExceptionType = x, Property = x.GetProperty("ErrorBitNumber", BindingFlags.Public | BindingFlags.Static) })
.Where(x => x.Property != null)
.Select(x => new { Key = (int)x.Property.GetValue(null, null)
Factory = (Func<BaseException>)(() => Activator.CreateInstance(x.ExceptionType)) });
foreach(var exception in exceptions)
registry.Register(exception.Key, exception.Factory);
实际获取异常实例的用法将使用注册表:
var exception = registry.GetInstance(errorBitNumber);
throw exception;