C# “有没有办法挤压?”;抛出新异常();变成一个物体?

C# “有没有办法挤压?”;抛出新异常();变成一个物体?,c#,exception,functional-programming,switch-expression,C#,Exception,Functional Programming,Switch Expression,其他一些高级语言,如Haskell和Perl 6,提供了允许抛出异常的语法糖,即使在语法需要对象的地方也是如此。当使用该值时,它的行为就好像它变成了一个抛出的异常(在下面的精心设计的示例中,这将是立即发生的): enum BuildMode{Debug,MemoryProfiling,Release}; bool-IsDebugMode(构建模式) { 返回模式==BuildMode.Debug?真 :mode==BuildMode.MemoryProfiling?真 :mode==BuildM

其他一些高级语言,如Haskell和Perl 6,提供了允许抛出异常的语法糖,即使在语法需要对象的地方也是如此。当使用该值时,它的行为就好像它变成了一个抛出的异常(在下面的精心设计的示例中,这将是立即发生的):

enum BuildMode{Debug,MemoryProfiling,Release};
bool-IsDebugMode(构建模式)
{
返回模式==BuildMode.Debug?真
:mode==BuildMode.MemoryProfiling?真
:mode==BuildMode.Release?false
:ThroweException(“未处理模式:+模式”);
}
上面的帮助程序允许从允许值但不允许语句的位置引发异常。我可以按如下方式编写此函数,尽管它没有Haskell或Perl 6代码那么酷,因为没有惰性计算:

T ThrowException<T>(string message)
{
#line hidden
    throw new Exception(message);
#line default
}
T ThrowException(字符串消息)
{
#隐藏线
抛出新异常(消息);
#行默认值
}
有没有什么规范的方法可以做到这一点,或者有什么好的理由不这样做

编辑:

事实上,在发布这篇文章之前,我没有尝试在C#7中使用
throw new Exception()
作为值。这或多或少就是答案。我将保留这一点,以防将来人们搜索与Perl 6的
Failure
类或Haskell的
error

C#7.0支持相同的C#是什么:


没有惰性评估,但您不再需要助手方法。

我怀疑您正在寻找添加到C#7中的方法

最常见的用法之一是空参数验证

var nameValue = value ?? throw new ArgumentNullException(paramName: nameof(value), message: "New name must not be null");
惰性评估

对于延迟求值,您必须返回函数或延迟求值:

Lazy<bool> IsDebugMode(BuildMode mode)
{
    bool isDebug() 
    {
        return mode == BuildMode.Debug ? true
            : mode == BuildMode.MemoryProfiling ? true
            : mode == BuildMode.Release ? false
            : throw new Exception(...);
   }

    return new Lazy<bool>(isDebug);
}
F#提供了一种更方便的语法,它还返回一个Lazy:

let isDebugMode mode = 
    match mode with
    | BuildMode.Debug -> true
    | BuildMode.Release -> false
    | _ -> failwith "Ouch!"

let isDbg = lazy (isDebugMode someMode)
...
//Can throw here
if (isDbg.Force() then 
   ...
使用Func执行相同的惰性计算:

Func<bool> IsDebugMode(BuildMode mode)
{
    bool isDebug() 
    {
        return mode == BuildMode.Debug ? true
            : mode == BuildMode.MemoryProfiling ? true
            : mode == BuildMode.Release ? false
            : throw new Exception(...);
   }

    return isDebug;
}
开关表达式

C#8将添加可能如下所示的开关表达式:

return mode switch {
    BuildMode.Debug           => true,
    BuildMode.MemoryProfiling => true,
    BuildMode.Release         => false,
    _ => throw new Exception (...)
};
Lazy<bool> IsDebugMode(BuildMode mode)
{
    bool isDebug() =>
        mode switch {
            BuildMode.Debug           => true,
            BuildMode.MemoryProfiling => true,
            BuildMode.Release         => false,
            _ => throw new Exception (...)
    };

   return new Lazy<bool>(isDebug);
}
惰性函数可能如下所示:

return mode switch {
    BuildMode.Debug           => true,
    BuildMode.MemoryProfiling => true,
    BuildMode.Release         => false,
    _ => throw new Exception (...)
};
Lazy<bool> IsDebugMode(BuildMode mode)
{
    bool isDebug() =>
        mode switch {
            BuildMode.Debug           => true,
            BuildMode.MemoryProfiling => true,
            BuildMode.Release         => false,
            _ => throw new Exception (...)
    };

   return new Lazy<bool>(isDebug);
}
Lazy IsDebugMode(构建模式)
{
bool isDebug()=>
模式开关{
BuildMode.Debug=>true,
BuildMode.MemoryProfiling=>true,
BuildMode.Release=>false,
_=>引发新异常(…)
};
返回新的Lazy(isDebug);
}

看起来有点像F#

给出的答案是正确的,但我将添加一个答案(到我自己的问题中),以指出在C#6及以下版本中模拟抛出表达式的理想方法。具有相同的名称和类似的API对于前向兼容性非常有用,因此这就是我所确定的帮助器类:

public class ThrowExpression<T>
{
    public ThrowExpression(string message)
    {
#line hidden
        throw new Exception(message);
#line default
    }

    // never used, but makes the compiler happy:
    public static implicit operator T(ThrowExpression<T> obj)
    {
        return default(T);
    }
}

各种修饰是可能的,例如接受不同的异常类型作为参数或通过附加的模板参数,但我打算保持简单,直到需要这些增强。

我担心在c中没有办法做到这一点,但我很乐意wrong@MatějŠtágl wellll。。。。扔expressions@PanagiotisKanavos如果抛出表达式是答案(它们可能是),那么我完全误解了OP希望它们抛出的原因;我以为他们想推迟throws@MarcGravell:我把他的问题理解为“我的(非懒惰的)助手方法是否有一个规范的替换?哦,顺便说一句,Haskell也允许对异常进行懒惰评估,我们也可以这样做吗?”@MarcGravel我仍在尝试将这个问题转换为熟悉的F和C术语。另外,代码没有显示任何延迟求值的尝试。它必须返回函数而不是实际值
return mode switch {
    BuildMode.Debug           => true,
    BuildMode.MemoryProfiling => true,
    BuildMode.Release         => false,
    _ => throw new Exception (...)
};
Lazy<bool> IsDebugMode(BuildMode mode)
{
    bool isDebug() =>
        mode switch {
            BuildMode.Debug           => true,
            BuildMode.MemoryProfiling => true,
            BuildMode.Release         => false,
            _ => throw new Exception (...)
    };

   return new Lazy<bool>(isDebug);
}
public class ThrowExpression<T>
{
    public ThrowExpression(string message)
    {
#line hidden
        throw new Exception(message);
#line default
    }

    // never used, but makes the compiler happy:
    public static implicit operator T(ThrowExpression<T> obj)
    {
        return default(T);
    }
}
public class ThrowExpression<T>
{
    private string message;
    public ThrowExpression(string message)
    {
        this.message = message;
    }

    public static implicit operator T(ThrowExpression<T> obj)
    {
#line hidden
        throw new Exception(message);
#line default
    }
}