web-dev-qa-db-ja.com

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

.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

これにより、「このコードはサックスであり、確認する必要があります」というコンパイラ警告が生成されます。カスタム属性の作成方法は知っていますが、Visual Studioでコンパイラ警告を生成するにはどうすればよいでしょうか。

110
Micah

更新

これは、Roslyn(Visual Studio 2015)で可能になりました。 ビルド a コードアナライザー でカスタム属性を確認できます


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

また、Visual StudioがObsoleteAttributeによって生成された警告をオンザフライでピックアップすることにも注意してください。これは非常に便利です。

役に立たないことを意味するのではなく、なぜあなたはそれを使うことに熱心ではないのか疑問に思っています...

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

C#標準から:-

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

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

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

25
ljs

これが機能するかどうかはわかりませんが、試してみる価値はあります。

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
{

}
93
Pablo Fernandez

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

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

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

#pragma message ( "text" )

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

44
Douglas Mayle

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

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

VS 2008(+ sp1)では、Solution&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'。

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

7
Tomasz Modelski

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

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

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

アル

6
user4089256

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

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

2
technophile

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

2
bdukes

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

1
bubi

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

1
johnny 5