自定义编译器警告
在.Net中使用ObsoleteAtribute时,它会给你提供编译器警告,告诉你对象/方法/属性已经过时,应该使用别的东西。 我目前正在做一个项目,需要大量的重构前员工代码。 我想写一个自定义属性,我可以用它来标记方法或属性,这些方法或属性会产生编写警告,给我写的消息。 像这样的东西
[MyAttribute("This code sux and should be looked at")] public sub DoEverything(){}
我想要这个产生一个编译器警告,说:“这个代码sux,应该看看”。 我知道如何创build一个自定义属性,问题是如何导致它在Visual Studio中生成编译器警告。
更新
现在可以使用Roslyn(Visual Studio 2015)。 您可以构build一个代码分析器来检查自定义属性
我不相信这是可能的。 ObsoleteAttribute被编译器专门处理,并在C#标准中定义。 为什么到底是ObsoleteAttribute不可接受? 在我看来,这正是它所devise的情况,并且达到了您所需要的!
另外请注意,Visual Studio也会随即提取由ObsoleteAttribute生成的警告,这非常有用。
不要吝啬,只是想知道为什么你不喜欢使用它…
不幸的是,ObsoleteAttribute是封闭的(可能部分是由于特殊的处理),因此你不能从中inheritance你自己的属性。
从C#标准: –
Obsolete属性用于标记不再使用的types和types的成员。
如果程序使用的是使用Obsolete属性装饰的types或成员,则编译器会发出警告或错误。 具体来说,如果没有提供错误参数,或者提供了错误参数并且其值为false,则编译器会发出警告。 如果指定了错误参数并且其值为true,则编译器会发出错误。
这难道不能总结你的需要吗?你不会做得比我想象的更好。
不知道这是否会奏效,但值得一试。
你不能扩展Obsolete,因为它的最后一个,但是也许你可以创build你自己的属性,并且把这个类标记为像这样废弃:
[Obsolete("Should be refactored")] public class MustRefactor: System.Attribute{}
然后,当您用“MustRefactor”属性标记方法时,编译警告可能会显示。
我说“也许”和“可能”,因为我没有尝试过。 请告诉我,如果它不起作用,我会删除答案。
问候!
更新:testing它。 它会生成一个编译时间警告,但是错误信息看起来很有趣,你应该自己看看并select。 这与你想达到的目标非常接近。
更新2:有了这个代码它产生了这个警告 (不是很好,但我不认为有更好的东西)。
public class User { private String userName; [TooManyArgs] // Will show warning: Try removing some arguments public User(String userName) { this.userName = userName; } public String UserName { get { return userName; } } [MustRefactor] // will show warning: Refactor is needed Here public override string ToString() { return "User: " + userName; } } [Obsolete("Refactor is needed Here")] public class MustRefactor : System.Attribute { } [Obsolete("Try removing some arguments")] public class TooManyArgs : System.Attribute { }
在一些编译器中,您可以使用#warning发出警告:
#warning "Do not use ABC, which is deprecated. Use XYZ instead."
在Microsoft编译器中,通常可以使用消息杂注:
#pragma message ( "text" )
你提到.Net,但没有说明你是用C / C ++还是C#编程。 如果你用C#编程,你应该知道C#支持#warning格式 。
目前,我们正在进行大量的重构,我们无法立即修复所有的问题。 我们只需使用#warning预处理命令,我们需要返回并查看代码。 它显示在编译器输出中。 我不认为你可以把它放在一个方法上,但是你可以把它放在方法里面,而且还是很容易find的。
public void DoEverything() { #warning "This code sucks" }
在VS 2008(+ SP1)#清除Soultion&重build解决scheme后,错误列表#warnings不正确显示,没有全部。 只有打开特定的类文件后才会在错误列表中显示一些警告。 所以我被迫使用自定义属性:
[Obsolete("Mapping ToDo")] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)] public class MappingToDo : System.Attribute { public string Comment = ""; public MappingToDo(string comment) { Comment = comment; } public MappingToDo() {} }
所以当我用它来标记一些代码
[MappingToDo("Some comment")] public class MembershipHour : Entity { // ..... }
它会产生这样的警告:
Namespace.MappingToDo已过时:“映射待办事项”。
我不能更改警告的文本,“有些评论”没有显示错误列表。 但它会跳到文件中的适当位置。 所以如果你需要改变这样的警告信息,创build各种属性。
你试图做的是滥用属性。 而是使用Visual Studio任务列表。 你可以像这样在代码中input注释:
//TODO: This code sux and should be looked at public class SuckyClass(){ //TODO: Do something really sucky here! }
然后从菜单中打开查看/任务列表。 任务列表有两个类别,用户任务和评论。 切换到评论,你会看到你所有的// Todo:在那里。 双击TODO将跳转到代码中的注释。
人
我不认为你可以。 据我所知,对ObsoleteAttribute的支持本质上是硬编码到C#编译器中的; 你不能直接做任何类似的事情。
你可以做的是使用MSBuild任务(或生成后事件)执行一个自定义工具对刚刚编译的程序集。 自定义工具将反映在程序集中的所有types/方法,并使用您的自定义属性,此时它可以打印到System.Console的默认或错误的TextWriters。
查看ObsoleteAttribute的源代码,看起来好像没有什么特别的东西来生成编译器警告,所以我倾向于使用@ technophile,并且说它是硬编码到编译器中的。 是否有一个原因,你不想只使用ObsoleteAttribute来生成您的警告消息?
有几条意见build议插入警告或附注。 过时的作品以一种非常不同的方式! 标记库L的function已过时,即使调用者程序不在库L中,程序调用该函数时也会引发过时的消息。只有在编译了L时,警告才会引发该消息。
这里是Roslyn的实现,所以你可以创build你自己的属性,给飞行的警告或错误。
我已经创build了一个属性Type Called IdeMessage,您将成为产生警告的属性:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)] public class IDEMessageAttribute : Attribute { public string Message; public IDEMessageAttribute(string message); }
为了做到这一点,你需要首先安装Roslyn SDK,并用分析器启动一个新的VSIX项目,我省略了一些不太相关的部分,比如你可以知道如何去做的信息,在你的分析器中,你这样做
public override void Initialize(AnalysisContext context) { context.RegisterSyntaxNodeAction(AnalyzerInvocation, SyntaxKind.InvocationExpression); } private static void AnalyzerInvocation(SyntaxNodeAnalysisContext context) { var invocation = (InvocationExpressionSyntax)context.Node; var methodDeclaration = (context.SemanticModel.GetSymbolInfo(invocation, context.CancellationToken).Symbol as IMethodSymbol); //There are several reason why this may be null eg invoking a delegate if (null == methodDeclaration) { return; } var methodAttributes = methodDeclaration.GetAttributes(); var attributeData = methodAttributes.FirstOrDefault(attr => IsIDEMessageAttribute(context.SemanticModel, attr, typeof(IDEMessageAttribute))); if(null == attributeData) { return; } var message = GetMessage(attributeData); var diagnostic = Diagnostic.Create(Rule, invocation.GetLocation(), methodDeclaration.Name, message); context.ReportDiagnostic(diagnostic); } static bool IsIDEMessageAttribute(SemanticModel semanticModel, AttributeData attribute, Type desiredAttributeType) { var desiredTypeNamedSymbol = semanticModel.Compilation.GetTypeByMetadataName(desiredAttributeType.FullName); var result = attribute.AttributeClass.Equals(desiredTypeNamedSymbol); return result; } static string GetMessage(AttributeData attribute) { if (attribute.ConstructorArguments.Length < 1) { return "This method is obsolete"; } return (attribute.ConstructorArguments[0].Value as string); }
没有CodeFixProvider可以将它从解决scheme中移除。