我已经知道在一段时间内对方法使用条件属性,但我发现它也可以在属性类上使用,所以我写了一些代码来测试它,但是它没有按预期执行。
此MSDN页面显示了如何在页面底部的属性类中使用条件属性:https://msdn.microsoft.com/en-us/library/4xssyw96%28v=vs.90%29.aspx。
顺便说一句,我正在使用Unity引擎。我不认为这应该重要,但我猜想。
这是我写的测试代码:
using System.Reflection;
using UnityEngine;
[System.Diagnostics.Conditional("UNITY_EDITOR")]
public class TestAttribute : System.Attribute
{
public string text;
public TestAttribute(string text)
{
this.text = text;
}
}
public class NewBehaviourScript : MonoBehaviour
{
[Test("This shouldn't exist on android")]
public void Awake()
{
#if UNITY_EDITOR
Debug.Log("This only gets logged in the Unity Editor, not in an Android build");
#endif
Debug.Log("Begin Attribute Test");
{
object[] attributes = typeof(NewBehaviourScript).GetMethod("Awake").GetCustomAttributes(true);
for (int i = 0; i < attributes.Length; i++)
{
Debug.Log(attributes[i]);// This logs TestAttribute both in the editor and on android.
}
TestAttribute att = attributes[0] as TestAttribute;
Debug.Log(att.text);// This logs "This shouldn't exist on android" both in the editor and on android.
}
Debug.Log("End Attribute Test");
Debug.Log("");
Debug.Log("Begin Method Test");
{
Method();// This only gets called in the Unity Editor, as expected from the conditional attribute.
MethodInfo methodInfo = typeof(NewBehaviourScript).GetMethod("Method");
Debug.Log(methodInfo);// this logs "void Method()" both in the editor and on android.
}
Debug.Log("End Method Test");
}
[System.Diagnostics.Conditional("UNITY_EDITOR")]
public void Method()
{
Debug.Log("This shouldn't exist on android either");
}
}
如果条件属性没有阻止GetCustomAttributes()获取测试属性,它实际上做了什么?
答案 0 :(得分:3)
让我简化你的例子:
[Conditional("DEBUG")]
class MyAttribute : Attribute {}
[MyAttribute]
class MyClass {}
当Conditional
属性应用于Attribute
派生类型时,如果Conditional
属性为MyClass
属性,则会导致从所有标记符号中删除该属性条件不成立。因此,在上面的示例中,MyAttribute
仅在调试版本中标记为DEBUG
;在发布版本中,[MyAttribute]
符号未定义(通常至少),因此编译器会从MyClass
的声明中删除private static void Main(string[] args)
{
var attribute = typeof(MyClass).GetCustomAttribute<MyAttribute>();
Console.WriteLine(attribute == null ? "missing" : "exists");
}
。您可以看到在使用反射时,尝试在调试和发布版本中运行以下代码:
Conditional
这将在调试版本中打印“exists”,在发布版本中打印“missing”。但是,只删除属性的应用程序;属性类本身仍存在于已编译的程序集中。这与JetBrains.Annotations
对方法的工作原理类似:只删除方法调用,方法仍然存在,例如可以通过反射调用。
为什么这有用? JetBrains在博客文章中描述了一个用例(请参阅“JetBrains.Annotations NuGet包”一节):他们有一个名为Conditional
的NuGet包,其中包含各种属性,可帮助他们的工具Resharper进行分析C#代码。但是,将这个NuGet包添加到您的项目中需要您随产品一起发送该程序集,即使您只是真正用它来编码;不是在运行时。他们所做的是:他们使用JetBrains.Annotations
属性注释程序集中的所有属性。这会导致编译器在编译期间去掉属性;然后注意到{{1}}从未被引用,从已编译的程序集中删除引用。因此,您无需随产品运送JetBrains的组件。
但是,我根本不知道这在Unity中是否有效。众所周知,Unity使用旧版本的Mono和C#编译器,因此可能存在阻止所有这些工作的错误。实际上,您的代码似乎表明这在Unity中确实无法正常工作。但是,如果您在独立的.NET应用程序中运行我或您的代码,它就可以运行。顺便说一句,您还可以使用较新版本的C#编译器来编译Unity可以引用的程序集;这应该允许您在Unity中解决此问题。
更新2018-03-17 :Unity的最新版本现在具有更新的Mono运行时和更新的C#编译器(并将很快更新到Microsofts C#编译器)。因此,有关条件编译属性的任何非标准行为都应在最新版本的Unity中修复。
答案 1 :(得分:1)
根据this文章,条件属性阻止编译器为void
返回函数发出MSIL,其中所述条件不存在。
我认为你第一次使用它是试图告诉系统如果条件不满足,那么TestAttribute属性不应该存在,而这似乎并不是什么呢?&#39 ; s for。
当您稍后获取方法Method
的MethodInfo时,我认为编译器已生成对Method
的调用,但它不应执行任何操作,因为没有要执行的代码。 (即该方法应立即返回。)
你实际上似乎没有打电话给Method
,只是获取有关它的信息,我认为这可能会误导你。