カスタムコンパイラの警告


115

.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でコンパイラの警告を生成する方法です。


これはC#ですか?私は、元のポスターが選択するつもりであったと推定して、これをC#(Cではなく)としてタグ付けし直すと思います。
Onorio Catenacci

13
それは有効なVBまたはC#ではありません...だからそれは何ですか...?!
ljs 2008

5
古い質問ですが、Roslynを使用してカスタムコンパイラ警告を定義できます。
RJカスバートソン

4
@jrummell Roslynで話す、コードアナライザー:johnkoerner.com/csharp/creating-your-first-code-analyzer
RJ Cuthbertson

2
@RJCuthbertson私はあなたのコメントを受け入れられた回答に移動し、それに値する注目を集めました。
jpaugh 2017年

回答:


27

更新

これは、Roslyn(Visual Studio 2015)で可能になりました。あなたはできるカスタム属性をチェックするコードアナライザー構築ます


それが可能だとは思いません。ObsoleteAttributeはコンパイラによって特別に扱われ、C#標準で定義されています。いったいなぜObsoleteAttributeは受け入れられないのですか?これはまさにそれが設計された状況であり、あなたが必要とするものを正確に達成しているように私には思えます!

また、Visual Studioは、ObsoleteAttributeによって生成された警告をその場で取得することにも注意してください。これは非常に便利です。

役に立たないという意味ではなく、なぜそれを使いたくないのか疑問に思うだけです...

残念ながら、ObsoleteAttributeはシールされている(おそらく一部は特別な処理が原因である)ため、そこから独自の属性をサブクラス化することはできません。

C#標準から:-

属性Obsoleteは、使用されなくなった型および型のメンバーをマークするために使用されます。

プログラムがObsolete属性で修飾された型またはメンバーを使用する場合、コンパイラーは警告またはエラーを発行します。具体的には、エラーパラメータが指定されていない場合、またはエラーパラメータが指定されていて値がfalseの場合、コンパイラは警告を発行します。errorパラメーターが指定され、値がtrueの場合、コンパイラーはエラーを発行します。

それはあなたのニーズを要約していませんか?...あなたは私が考えていないよりもうまくやるつもりはありません。


14
同じものを探しています。廃止された '作品'ですが、コードは実際には、リファクタリングのために不完全ではありません。
g。

11
私は@gに同意します。おそらく元の作者です。廃止とは、廃止されたことを意味し、使用しないでください。「これはコンパイルされますが、実際にはa)機能を完了するか、b)リファクタリングする必要がある」というフラグを立てたいです。これは、開発時間属性の詳細になります。// TODO:などのタスクも機能しますが、多くの人が使用していないと思いますので、それらは使用しませんが、コンパイラの警告を定期的に確認します。
MikeJansen

8
[Obsolete]タグを使用しないもう1つの理由は、プロパティでXmlSerializationを実行する必要がある場合に問題を引き起こす可能性があることです。追加[Obsolete]タグも追加[XmlIgnore]舞台裏属性を。
burnttoast11 2012

6
時代遅れです。廃止された場合、そのメソッドを呼び出すコードのすべての行で警告が表示されます。私はそれがポスターが望んでいることだとは思いません(少なくとも私が検索してこの質問を見つけたときに私が望んでいることではありません)。質問が求めているのは、関数が使用されている場所ではなく、関数の定義に警告が表示されることだと思いました。
Nick

最高の答えではありません。それを使用しない理由を思い付くことができないと考える場合は-1は批判に値します。この態度は信頼性を落とします。
Mike Socha III 2016年3

96

これは試す価値があります。

最終版であるため、廃止を拡張することはできませんが、独自の属性を作成し、そのクラスを次のように廃止としてマークすることができます。

[Obsolete("Should be refactored")]
public class MustRefactor: System.Attribute{}

次に、「MustRefactor」属性でメソッドをマークすると、コンパイル警告が表示されます。コンパイル時の警告が生成されますが、エラーメッセージはおかしく見えます。自分で確認して選択してください。これは、あなたが達成したかったことと非常に近いものです。

更新:このコードを使用すると、警告が生成されます(あまり良くありませんが、もっと良いものはないと思います)。

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
{

}

それが生成するものを貼り付けることができますか?私は興味がある。
ミカ

1
プロパティ/メソッドが呼び出されない場合でも、コンパイル警告がトリガーされます。
Rolf Kristensen、2010

1
ここに良い提案があります。私は同じことをしようとしていて、NotImplementedExceptionsをスローするだけになりました。コンパイル時には表示されず、コードがたまたま実行された場合にのみ実行時に表示されるため、最善の解決策ではありません。これをやってみます。
MonkeyWrench

1
ObsolteAttributeがDebuggerDisplayAttributeと同じように式をサポートできれば、すばらしいことではないでしょうか。visualstudio.uservoice.com/forums/121579-visual-studio/...
jpierson

IDisposableこれらの廃止されたクラスを実装する場合は、危険なテストコードをusingブロックでラップできることを意味します。このように:using(new MustRefactor()){DodgyCode();}。その後、完了したらすべての使用法を見つけることができます。今、これをSleepforループ内のスレッドに使用しています。デバッグの目的で人為的にスローダウンする必要があります。
Iain Fraser

48

一部のコンパイラでは、#warningを使用して警告を発行できます。

#warning "Do not use ABC, which is deprecated. Use XYZ instead."

Microsoftコンパイラでは、通常、メッセージプラグマを使用できます。

#pragma message ( "text" )

.Netについて言及しましたが、C / C ++とC#のどちらでプログラミングしているかを指定しませんでした。C#でプログラミングしている場合は、C#が#warning形式をサポートしていることを知っておく必要があります


1
#warningまたは#pragmaはプリプロセッサディレクティブであるため、micahの元の同僚のコードの存在に関係なく実行され、属性とはまったく対話しません。これを達成するための唯一の手段はかなり時代遅れのものです...
ljs

39

現在、多くのリファクタリングの真っ只中にあり、すぐにすべてを修正することはできませんでした。#warning preprocコマンドを使用して、コードに戻って確認する必要があります。コンパイラの出力に表示されます。メソッドに置くことはできないと思いますが、メソッドのすぐ内側に置くこともでき、しかも簡単に見つけることができます。

public void DoEverything() {
   #warning "This code sucks"
}

7

VS 2008(+ sp1)では、Clean Soultion&Rebuild Solutionの後、#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は廃止されました: 'Mapping ToDo'。

警告のテキストを変更できません。「一部のコメント」にエラーリストが表示されません。しかし、ファイル内の適切な場所にジャンプします。したがって、そのような警告メッセージを変更する必要がある場合は、さまざまな属性を作成します。


6

あなたがしようとしているのは、属性の誤用です。代わりに、Visual Studioタスクリストを使用してください。次のようにコードにコメントを入力できます。

//TODO:  This code sux and should be looked at
public class SuckyClass(){
  //TODO:  Do something really sucky here!
}

次に、メニューから[表示] / [タスクリスト]を開きます。タスクリストには、ユーザータスクとコメントの2つのカテゴリがあります。コメントに切り替えると、// Todo:がすべて表示されます。TODOをダブルクリックすると、コード内のコメントにジャンプします。

アル


1
私はこれがより好ましい解決策だと思っています
Samuel

1
関数を「量産コードで呼び出されないようにする」などのマークを付けたい場合はどうでしょうか。したがって、関数またはクラスが呼び出されるかインスタンス化された場合に起動し、コンパイルされた場合に起動しないようにする必要があります。
ジェシーペッパー

2

できないと思います。私の知る限り、ObsoleteAttributeのサポートは基本的にC#コンパイラにハードコードされています。同様のことを直接行うことはできません。

実行できるのは、コンパイルしたばかりのアセンブリに対してカスタムツールを実行するMSBuildタスク(またはビルド後のイベント)を使用することです。カスタムツールは、アセンブリ内のすべてのタイプ/メソッドを反映し、カスタム属性を使用します。この時点で、System.ConsoleのデフォルトまたはエラーのTextWriterに出力できます。


2

ObsoleteAttributeのソースを見ると、コンパイラの警告を生成するために特別なことをしているようには見えないため、@ technophileを使用して、コンパイラにハードコードされていると言いがちです。警告メッセージを生成するためにObsoleteAttributeを使用したくない理由はありますか?


コード以外の特別な理由は必ずしも時代遅れではありません。
ミカ

1
C#仕様ではコンパイラーによって特別に扱われるように指定されています。私の答えを確認してください:-)。Micah-「属性Obsoleteは、使用されなくなった型および型のメンバーをマークするために使用されます。」仕様から。該当しませんか?...
ljs 2008

誰かが疑問に思ったとしても、これを行うためのソースコードにはC#コードはありません。referencesource.microsoft.com/#mscorlib/system/...
パヴェルマッハ

1

警告またはプラグマを挿入することを提案するコメントがいくつかあります。時代遅れは非常に異なる方法で動作します!ライブラリLの関数が廃止されたことを示すと、呼び出し元プログラムがライブラリLにない場合でも、プログラムが関数を呼び出すと、廃止されたメッセージが表示されます。警告が表示されるのは、Lのコンパイル時のみです。


1

これがRoslyn実装です。そのため、警告やエラーをその場で出す独自の属性を作成できます。

IdeMessage警告を生成する属性になるType Called 属性を作成しました。

[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はありません。ソリューションから削除できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.