我想编写一个扩展方法,当某些条件满足时,生成和 thow 泛型异常。我想出了这段代码:
internal static TSource ConditionalThrow<TSource, TException>(this TSource source, Func<TSource, bool> throwCondition, TException exception, params object[] arguments) where TException : Exception
{
if (throwCondition(source))
{
throw CreateInstance(exception.GetType(), arguments) as Exception;
}
else
{
return source;
}
}
问题在于用户必须自己初始化exception
参数,因此可以简化为:
internal static TSource ConditionalThrow<TSource, TException>(this TSource source, Func<TSource, bool> throwCondition, TException exception) where TException : Exception
{
if (throwCondition(source))
{
throw exception;
}
else
{
return source;
}
}
但我希望该扩展会产生错误。我想是通过Type
代替TException
,但我不能将其限制为Exception
类型。
internal static TSource ConditionalThrow<TSource>(this TSource source, Func<TSource, bool> throwCondition, Type exception)
{
if (throwCondition(source))
{
throw CreateInstance(exception, arguments) as Exception;
}
else
{
return source;
}
}
我能否实际实现生成和 thow 一般性异常的扩展?
我调查了this,但没有成功。
答案 0 :(得分:2)
是的,就像使用它一样:
internal static TSource ConditionalThrow<TSource>(this TSource source, Func<TSource, bool> throwCondition, Type exceptionType, params object[] arguments)
{
if (!typeof(Exception).IsAssignableFrom(exceptionType))
throw new ArgumentException("exceptionType is not an Exception");
if (throwCondition(source))
throw Activator.CreateInstance(exceptionType, arguments) as Exception;
return source;
}
internal static TSource ConditionalThrow<TSource>(this TSource source, Func<TSource, bool> throwCondition, Func<Exception> exeptionBuilder)
{
if (throwCondition(source))
throw exeptionBuilder();
return source;
}
让我们使用示例类来测试我们的解决方案
public class Temp
{
public string Name { get; set; }
}
public class MyException : Exception
{
public MyException(string name, string age)
: base($"Name: {name} and Age: {age}")
{ }
public MyException()
: base("No parameter")
{ }
}
try
{
new Temp().ConditionalThrow(t => true, typeof(MyException), "Alberto", "25");
}
catch (MyException ex)
{
Console.WriteLine(ex.Message);
}
try
{
new Temp().ConditionalThrow(t => true, typeof(MyException));
}
catch (MyException ex)
{
Console.WriteLine(ex.Message);
}
try
{
new Temp().ConditionalThrow(t => true, typeof(string));
}
catch (ArgumentException ex)
{
Console.WriteLine(ex.Message);
}
姓名:Alberto和年龄:25
无参数
exceptionType不是异常
工作样本:https://dotnetfiddle.net/brIjq9
try
{
new Temp().ConditionalThrow(t => true, () => new MyException("Alberto", "25"));
}
catch (MyException ex)
{
Console.WriteLine(ex.Message);
}
try
{
new Temp().ConditionalThrow(t => true, () => new MyException());
}
catch (MyException ex)
{
Console.WriteLine(ex.Message);
}
姓名:Alberto和年龄:25
无参数
答案 1 :(得分:1)
很明显,指定源类型和异常类型是更好的设计,允许应用泛型类型约束。然后,为了消除明确指定TSource
和TException
的必要性,您可以将ConditionalThrow
分解为两个方法,如下所示:
internal static void Throw<TException>(this bool condition, params object[] args) where TException : Exception
{
if (condition) throw (Exception)Activator.CreateInstance(typeof(TException), args);
}
internal static bool If<TSource>(this TSource source, Func<TSource,bool> condition)
{
return condition(source);
}
然后用法就是这样:
10.If(x => x>0).Throw<Exception>();
但是,此不允许允许source
从Throw
返回。正如OP正确建议的那样,这里的解决方法是使用另一种确保返回source
的方法来包装调用:
internal static TSource Do<TSource> (this TSource source, Action<TSource> action)
{
action(source);
return source;
}
int a = 10.Do(s => s.If(x => x>0).Throw<Exception>()) + 1;
另一种选择是将异常的 instatiation 分解为一个条件执行的委托,如下所示:
internal static TSource ThrowIf<TSource>(this TSource source, Func<TSource,bool> condition, Func<Exception> buildException)
{
if (condition(source))
throw buildException();
else
return source;
}
然后用法就是这样:
int a = 10.ThrowIf(x => x>0, () => new Exception()) + 1;
虽然这需要一个() =>
lambda构造,但是如果没有抛出,source
可以返回,并且不需要像前案例。
第二种方法的一大优点是异常实例化和异常参数的评估都是惰性评估的,即仅在真正应该抛出异常的情况下。这个可能是一个严重的正记忆和性能因素,消除了非异常代码路径中的副作用。
答案 2 :(得分:0)
您可以使用new()
通用约束,以便在方法中创建例外。缺点是你有来指定通用参数,不能推断它们。
internal static TSource ConditionalThrow<TSource, TException>(this TSource source, Func<TSource, bool> throwCondition)
where TException : Exception, new()
{
if (throwCondition(source)) {
throw new TException();
} else {
return source;
}
}
或者你可以使用自己创建异常的当前方法,但是通过泛型参数而不是Type参数指定类型。
internal static TSource ConditionalThrow<TSource, TException>(this TSource source, Func<TSource, bool> throwCondition)
where TException : Exception
{
if (throwCondition(source)) {
throw CreateInstance(typeof(TException), arguments) as Exception;
} else {
return source;
}
}