-
03-07-2019 - |
题
在.Net中使用ObsoleteAtribute时,它会为您提供编译器警告,告诉您对象/方法/属性已过时,应该使用其他东西。我目前正在开发一个需要大量重构前雇员代码的项目。我想编写一个自定义属性,我可以用它来标记将生成编译器警告的方法或属性,这些警告会给出我写的消息。像这样的东西
[MyAttribute("This code sux and should be looked at")]
public void DoEverything()
{
}
<MyAttribute("This code sux and should be looked at")>
Public Sub DoEverything()
End Sub
我希望这会生成一个编译器警告,上面写着“此代码sux,应该查看”。我知道如何创建自定义属性,问题是我如何使它在visual studio中生成编译器警告。
解决方案
更新
现在可以使用Roslyn(Visual Studio 2015)。您可以构建 代码分析器检查自定义属性
我不相信这是可能的。 ObsoleteAttribute由编译器专门处理,并在C#标准中定义。为什么ObsoleteAttribute不被接受?在我看来,这正是它所针对的情况,并准确地实现了您的需求!
另请注意,Visual Studio也会即时获取由ObsoleteAttribute生成的警告,这非常有用。
不要故意无益,只是想知道你为什么不热衷于使用它......
不幸的是,ObsoleteAttribute是密封的(可能部分是由于特殊处理),因此您无法从中继承自己的属性。
来自C#标准: -
属性Obsolete用于标记 类型和应该类型的成员 不再使用。
如果程序使用类型或成员 用过时装饰的 属性,编译器发出一个 警告或错误。具体来说, 如果没有错误,编译器会发出警告 提供参数,或者如果错误 参数提供并具有 价值假。编译器发出一个 错误参数是错误 指定并且值为true。
这不能总结你的需求吗?......你不会做得比我想的更好。
其他提示
不知道这是否有效,但值得一试。
你不能扩展Obsolete,因为它是最终的,但也许你可以创建自己的属性,并将该类标记为过时,如下所示:
[Obsolete("Should be refactored")]
public class MustRefactor: System.Attribute{}
然后当您使用“MustRefactor”标记您的方法时属性,编译警告可能会显示。
我说“也许”和“可能”因为我没试过这个请告诉我,如果它不起作用,我会删除答案。
问候!
更新:测试过它。它会生成编译时警告,但错误消息看起来很有趣,您应该亲眼看到并选择。这非常接近您想要实现的目标。
<强> UPDATE2: 使用此代码它会生成这个警告(不是很好,但我认为没有更好的东西)。
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:
#pragma message ( "text" )
你提到过.Net,但没有说明你是用C / C ++还是用C#编程。如果您使用C#进行编程,那么您应该知道 C#支持#warning格式。
我们目前正处于大量重构的中间,我们无法立即解决所有问题。我们只需使用#warning preproc命令,我们需要返回并查看代码。它出现在编译器输出中。我不认为你可以把它放在一个方法上,但你可以把它放在方法中,而且它仍然很容易找到。
public void DoEverything() {
#warning "This code sucks"
}
在VS 2008(+ sp1)中#warnings在Clean Soultion&amp;之后的错误列表中无法正确显示重建解决方案,不是全部。 仅在打开特定类文件后,错误列表中会显示一些警告。 所以我被迫使用自定义属性:
[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已过时: '映射待办事项'。
我无法更改警告文本,“有些评论”未显示错误列表。 但它会跳到文件中的适当位置。 因此,如果您需要更改此类警告消息,请创建各种属性。
您要做的是滥用属性。而是使用Visual Studio任务列表。您可以在代码中输入注释,如下所示:
//TODO: This code sux and should be looked at
public class SuckyClass(){
//TODO: Do something really sucky here!
}
然后从菜单中打开“查看/任务列表”。任务列表有两个类别,用户任务和注释。切换到评论,你会看到你的所有// Todo:那里。双击TODO将跳转到代码中的注释。
的Al
我认为你不能。据我所知,对ObsoleteAttribute的支持本质上是硬编码到C#编译器中;你不能直接做任何类似的事。
您可以做的是使用MSBuild任务(或构建后事件)对正常编译的程序集执行自定义工具。自定义工具将反映程序集中的所有类型/方法并使用您的自定义属性,此时它可以打印到System.Console的默认值或错误TextWriters。
查看 ObsoleteAttribute 的来源,它没有看起来它正在做一些特殊的事情来生成编译器警告,所以我倾向于使用@ technophile 并说它被硬编码到编译器中。您是否有理由不想使用 ObsoleteAttribute 生成警告信息?
有几条评论建议插入警告或编译指示。 过时的工作方式非常不同! 将库L的函数标记为过时,即使调用者程序不在库L中,当程序调用函数时,过时的消息也会引发。警告仅在编译L时才会引发消息。
这是Roslyn实现,因此您可以创建自己的属性,即时提供警告或错误。
我创建了一个属性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 e.g 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可以将其从解决方案中删除。