获取表示c#中用作函数参数的表达式的字符串

本文关键字:参数 表达式 字符串 函数 表示 获取 | 更新日期: 2023-09-27 18:01:42

我正在使用c#开发Unity3D,并决定有一个断言函数将是有用的。(在Unity3D中,System.Diagnostics.Debug.Assert 存在,但不做任何事情。)

作为主要使用c++的开发人员,我习惯于通过预处理字符串化操作符来断言包含断言表达式的消息。也就是说,给定一个失败的形式ASSERT(x > 0, "x should not be zero.")断言,在运行时消息中显示的消息可以包含文本"x> 0"。我希望能够在c#中做同样的事情。

我知道ConditionalAttribute和DebuggerHiddenAttribute,我使用两者(尽管后者似乎被MonoDevelop捆绑在Unity的自定义构建所忽略)。在寻找解决这个问题的方法时,我在System.Runtime.CompilerServices命名空间中遇到了三个属性,这些属性似乎与我要做的事情有关:CallerFilePathAttribute, CallerLineNumberAttribute和CallerMemberNameAttribute。(在我的实现中,我使用System.Diagnostics.StackTracefNeedFileInfo == true代替。)

我想知道是否有任何反射魔法(似乎不太可能)或属性魔法(似乎更有可能),可以帮助我实现与我在c++中习惯的相同功能。

获取表示c#中用作函数参数的表达式的字符串

如果你传递一个表达式,你可以接近你想要的x > 0:

[Conditional("DEBUG")]
public static void Assert(Expression<Func<bool>> assertion, string message, [CallerMemberName] string memberName = "", [CallerFilePath] string sourceFilePath = "", [CallerLineNumber] int sourceLineNumber = 0)
{
    bool condition = assertion.Compile()();
    if (!condition)
    {
        string errorMssage = string.Format("Failed assertion in {0} in file {1} line {2}: {3}", memberName, sourceFilePath, sourceLineNumber, assertion.Body.ToString());
        throw new AssertionException(message);
    }
}

你需要这样调用它:

Assert(() => x > 0, "x should be greater than 0");

自从这个问题在10年前发布以来,c#世界在。net 5(和。net core 3.1)中发生了一点变化,有一个内置的属性可以将表达式作为字符串获取,我不认为Unity支持这个(根据问题),但他们说他们正在努力从.Net Framework切换到.Net Core+

CallerArgumentExpression这个工作的方式是编译器将看到CallerArgumentExpression属性并查看你在那里指定的参数,如果你没有明确地说表达式是什么,编译器将取组成表达式的文本并静态编译它。

这将被实现为:

[Conditional("DEBUG")]
public static void Assert(bool condition, string message, 
[CallerArgumentExpression("condition")] string expression = null)
{
    if (!condition)
    {
        string errorMssage = $"{message} - '{expression}'";
        throw new AssertionException(message);
    }
}

用法如下:

Assert(x > 0, "x should be greater than 0");

这将导致断言消息

"x should be greater than 0 - 'x > 0'"