换句话说,如果每个类都没有(“必须拥有”)自定义属性(例如作者和作者),则可以创建甚至不编译的程序集(假设检查代码未被删除)。版本)?
以下是我在运行时查询时使用的代码:
using System;
using System.Reflection;
using System.Collections.Generic;
namespace ForceMetaAttributes
{
[System.AttributeUsage ( System.AttributeTargets.Method, AllowMultiple = true )]
class TodoAttribute : System.Attribute
{
public TodoAttribute ( string message )
{
Message = message;
}
public readonly string Message;
}
[System.AttributeUsage ( System.AttributeTargets.Class |
System.AttributeTargets.Struct, AllowMultiple = true )]
public class AttributeClass : System.Attribute
{
public string Description { get; set; }
public string MusHaveVersion { get; set; }
public AttributeClass ( string description, string mustHaveVersion )
{
Description = description;
MusHaveVersion = mustHaveVersion ;
}
} //eof class
[AttributeClass("AuthorName" , "1.0.0")]
class ClassToDescribe
{
[Todo ( " A todo message " )]
static void Method ()
{ }
} //eof class
//how to get this one to fail on compile
class AnotherClassToDescribe
{
} //eof class
class QueryApp
{
public static void Main()
{
Type type = typeof(ClassToDescribe);
AttributeClass objAttributeClass;
//Querying Class Attributes
foreach (Attribute attr in type.GetCustomAttributes(true))
{
objAttributeClass = attr as AttributeClass;
if (null != objAttributeClass)
{
Console.WriteLine("Description of AnyClass:\n{0}",
objAttributeClass.Description);
}
}
//Querying Class-Method Attributes
foreach(MethodInfo method in type.GetMethods())
{
foreach (Attribute attr in method.GetCustomAttributes(true))
{
objAttributeClass = attr as AttributeClass;
if (null != objAttributeClass)
{
Console.WriteLine("Description of {0}:\n{1}",
method.Name,
objAttributeClass.Description);
}
}
}
//Querying Class-Field (only public) Attributes
foreach(FieldInfo field in type.GetFields())
{
foreach (Attribute attr in field.GetCustomAttributes(true))
{
objAttributeClass= attr as AttributeClass;
if (null != objAttributeClass)
{
Console.WriteLine("Description of {0}:\n{1}",
field.Name,objAttributeClass.Description);
}
}
}
Console.WriteLine ( "hit Enter to exit " );
Console.ReadLine ();
} //eof Main
} //eof class
} //eof namespace
//uncomment to check whether it works with external namespace
//namespace TestNamespace {
// class Class1 { }
// class Class2 { }
//}
编辑:只是为了证明我的答案选择。 我认为casperOne提供了问题的正确答案。
然而,问这个问题的理由似乎是weak。可能我应该开始使用一些外部工具,例如: FinalBuilder 或者使用Pex,Nunit或其他单元测试框架创建单元测试来检查这个“需求”......
修改
我在执行检查的答案末尾添加了一个小code snippet控制台程序...随意评论,批评或建议改进
我再一次意识到这个“要求”应该在“登记”之前作为单元测试的一部分来实现
答案 0 :(得分:7)
不,不可能挂钩程序集的编译并检查它是否存在。
然而你可以挂钩到构建过程,它不仅仅是运行编译器。您可以创建一个自定义的MSBUILD任务(或NAnt,如果您正在使用它),它在构建后通过反射检查程序集,如果它没有所需的属性,则会使构建失败。
当然,你应该仍然在代码中验证这一点。您尝试做的不是正确运行时检查的良好替代品。
答案 1 :(得分:4)
您可以运行反映在DLL上的后构建步骤来执行您想要的操作。
您必须编写一个加载DLL并反映类型的命令行应用程序。然后,您将该命令行应用程序作为构建后步骤运行。我过去做过这个。假设您了解反射API,这并不是非常困难。
PostSharp这样做可以实现面向方面的编程。实际上很酷。
答案 2 :(得分:1)
属性仅限运行时间。但是:
可以在FXCop(静态分析)中创建一个规则,如果未定义该属性,该规则将失败,并且您的构建/签入过程可以检查该规则并且适当地失败。
答案 3 :(得分:1)
我不知道有什么方法可以挂钩C#编译过程,但是您可以采用不同的方法并创建在post build事件上启动的自定义工具,该工具可以加载您的程序集并对其进行反映。根据工具返回的内容,整个构建过程将导致成功或失败,因此您可能只是使用工具返回错误并使构建失败,同时提供有关写入控制台的失败的更多详细信息。
答案 4 :(得分:1)
对我来说,这似乎更像是一个测试问题,而不是一个编译问题。也就是说,你问“我怎么知道我的代码写得正确?”其中“正确书写”具有(除其他外)所有类用特定属性修饰的内涵。我会考虑编写单元测试来验证您的属性包含规则实际上是遵循的。您可以让构建(和/或签入)进程在构建之后(签入之前)运行此特定测试集,作为成功构建(签入)的条件。它不会破坏编译,因为需要完成才能运行测试,但它会破坏构建,可以这么说。
答案 5 :(得分:0)
//PLEASE COMMENT IF YOU FIND BUGS OR SUGGEST IMPROVEMENTS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace MustHaveAttributes
{
[AttributeClass ( "Yordan Georgiev", "1.0.0" )]
class Program
{
static void Main ( string [] args )
{
bool flagFoundCustomAttrOfTypeAttributeClass = false;
Console.WriteLine ( " START " );
// what is in the assembly
Assembly a = Assembly.Load ( "MustHaveAttributes" );
Type[] types = a.GetTypes ();
foreach (Type t in types)
{
object[] arrCustomAttributes = t.GetCustomAttributes ( true );
if (arrCustomAttributes == null || arrCustomAttributes.GetLength ( 0 ) == 0)
{
//DO NOT CHECK IN
ExitProgram ( t, "Found class without CustomAttributes" );
}
foreach (object objCustomAttribute in arrCustomAttributes)
{
Console.WriteLine ( "CustomAttribute for type is {0}", t );
if (objCustomAttribute is AttributeClass)
flagFoundCustomAttrOfTypeAttributeClass = true;
}
if (flagFoundCustomAttrOfTypeAttributeClass == false)
{ //DO NOT CHECK IN
ExitProgram ( t, "Did not found custom attribute of type AttributeClass" );
}
Console.WriteLine ( "Type is {0}", t );
}
Console.WriteLine ("{0} types found", types.Length );
//NOW REQUIREMENTS IS PASSED CHECK IN
Console.WriteLine ( " HIT A KEY TO EXIT " );
Console.ReadLine ();
Console.WriteLine ( " END " );
}
static void ExitProgram ( Type t, string strExitMsg )
{
Console.WriteLine ( strExitMsg );
Console.WriteLine ( "Type is {0}", t );
Console.WriteLine ( " HIT A KEY TO EXIT " );
Console.ReadLine ();
System.Environment.Exit ( 1 );
}
} //eof Program
//This will fail even to compile since the constructor requires two params
//[AttributeClass("OnlyAuthor")]
//class ClassOne
//{
//} //eof class
////this will not check in since this class does not have required custom
////attribute
//class ClassWithoutAttrbute
//{ }
[AttributeClass("another author name " , "another version")]
class ClassTwo
{
} //eof class
[System.AttributeUsage ( System.AttributeTargets.Class |
System.AttributeTargets.Struct, AllowMultiple = true )]
public class AttributeClass : System.Attribute
{
public string MustHaveDescription { get; set; }
public string MusHaveVersion { get; set; }
public AttributeClass ( string mustHaveDescription, string mustHaveVersion )
{
MustHaveDescription = mustHaveDescription;
MusHaveVersion = mustHaveVersion;
}
} //eof class
} // eof namespace
答案 6 :(得分:0)
现在完全可以通过编写 Roslyn 分析器来使用。您可以使用语法树或语义模型。
(建议使用后者,因为如何引用属性名称很复杂,例如使用 using
别名)。