사용자 정의 컴파일러 경고


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

5
오래된 질문이지만 이제 Roslyn을 사용하여 사용자 정의 컴파일러 경고를 정의 할 수 있습니다.
— RJ Cuthbertson

4
@jrummell에서 로슬린은, 코드 분석기를 말하는 : johnkoerner.com/csharp/creating-your-first-code-analyzer
— RJ Cuthbertson

2
@RJCuthbertson 나는 귀하의 의견을 수용 된 답변으로 옮겼습니다.
— jpaugh

답변:


27

최신 정보

이제 Roslyn (Visual Studio 2015)으로 가능합니다. 당신은 할 수 있습니다 구축 코드 분석기를 사용자 지정 특성을 확인하기 위해


나는 그것이 가능하다고 믿지 않는다. ObsoleteAttribute는 컴파일러에서 특별히 처리되며 C # 표준에 정의되어 있습니다. 왜 ObsoleteAttribute가 허용되지 않습니까? 이것이 정확히 설계된 상황 인 것처럼 보이며 필요한 것을 정확하게 달성합니다!

또한 Visual Studio는 ObsoleteAttribute에 의해 생성 된 경고도 즉석에서 선택하므로 매우 유용합니다.

도움이되지 않는다는 뜻이 아니라, 왜 그것을 사용하고 싶지 않은지 궁금해합니다.

불행히도 ObsoleteAttribute는 봉인되어 있습니다 (아마 부분적으로 특수 처리로 인해). 따라서 여기에서 자신의 속성을 하위 클래스화할 수 없습니다.

C # 표준에서 :-

Obsolete 속성은 더 이상 사용하지 않아야하는 유형 및 유형의 멤버를 표시하는 데 사용됩니다.

프로그램이 Obsolete 특성으로 데코 레이팅 된 유형 또는 멤버를 사용하는 경우 컴파일러는 경고 또는 오류를 발행합니다. 특히, 오류 매개 변수가 제공되지 않거나 오류 매개 변수가 제공되고 값이 false 인 경우 컴파일러는 경고를 발행합니다. 오류 매개 변수가 지정되고 값이 true 인 경우 컴파일러는 오류를 발행합니다.

그것은 당신의 필요를 요약하지 않습니까? ... 당신은 내가 생각하지 않는 것보다 더 잘하지 않을 것입니다.


14
나는 같은 것을 찾고 있습니다. 구식 '작동'하지만 코드는 리팩토링으로 인해 불완전한 것처럼 실제로 쓸모없는 것은 아닙니다.
— g.

11
나는 @g와 아마도 원저자에 동의합니다. Obsolete는 사용하지 않는다는 의미입니다. 나는 무언가를 "이게 컴파일되지만 우리는 정말로 a) 기능을 완성하거나 b) 리팩토링해야한다"라고 플래그를 지정하고 싶습니다. 개발 시간 속성에 가깝습니다. 또한 작업은 작동합니다. 예 : // TODO :하지만 많은 사람들이 사용하지 않는다고 생각하므로 사용하지 않지만 컴파일러 경고를 정기적으로 검토합니다.
— MikeJansen 2012 년

8
[Obsolete]태그 를 사용하지 않는 또 다른 이유 는 속성으로 XmlSerialization을 수행해야하는 경우 문제가 발생할 수 있기 때문입니다. 추가 중 [Obsolete]태그도 추가 [XmlIgnore]뒤에서 속성을.
— burnttoast11

6
구식은 다릅니다. Obsolete는 해당 메서드를 호출하는 모든 코드 줄에 경고를 제공합니다. 나는 그것이 포스터가 원하는 것이라고 생각하지 않습니다 (적어도 검색을 하고이 질문을 찾았을 때 내가 원하는 것은 아닙니다). 나는 그 질문이 함수의 정의에 대한 경고가 사용되는 곳이 아니라 경고를 찾는 것이라고 생각했습니다.
— Nick

최고의 대답은 아닙니다. -1 사용하지 않는 이유를 찾을 수 없다고 생각하는 것은 비판의 가치가 있습니다. 이러한 태도는 진정성을 저해합니다.
— Mike Socha III

96

이것은 시도 할 가치가 있습니다.

최종적이므로 Obsolete를 확장 할 수 없지만 자신 만의 속성을 만들고 다음과 같이 해당 클래스를 구식으로 표시 할 수 있습니다.

[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
{

}

생성 된 것을 붙여 넣을 수 있습니까? 궁금해.
— Micah

1
Property / Method가 호출되지 않아도 컴파일 경고가 발생합니다.
— Rolf Kristensen

1
여기에 좋은 제안이 있습니다. 나는 똑같은 일을 찾고 있었고 결국 NotImplementedExceptions를 던졌습니다. 컴파일 타임에 나타나지 않기 때문에 최상의 솔루션은 아니며 코드가 실행되는 경우 런타임에만 표시됩니다. 직접 시도해 보겠습니다.
— MonkeyWrench 2011 년

1
ObsolteAttribute가 DebuggerDisplayAttribute와 같은 식을 지원할 수 있다면 좋지 않을까요? 그러면 정말 멋진 일을 할 수 있습니다. visualstudio.uservoice.com/forums/121579-visual-studio/…
— jpierson

IDisposable이러한 쓸모없는 클래스에서 구현 하면 엉뚱한 테스트 코드를 using블록으로 래핑 할 수 있습니다 . 이렇게 : using(new MustRefactor()){DodgyCode();}. 그런 다음 완료되면 모든 사용법을 찾을 수 있습니다. Sleep디버깅을 위해 인위적으로 속도를 늦춰야하는 for 루프 내부의 스레드에 지금 이것을 사용하고 있습니다.
— Iain Fraser

48

일부 컴파일러에서는 #warning을 사용하여 경고를 발행 할 수 있습니다.

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

Microsoft 컴파일러에서는 일반적으로 pragma 메시지를 사용할 수 있습니다.

#pragma message ( "text" )

.Net에 대해 언급했지만 C / C ++ 또는 C #으로 프로그래밍하는지 여부는 지정하지 않았습니다. C #으로 프로그래밍하는 경우 C #이 #warning 형식을 지원 한다는 사실을 알아야 합니다 .


1
#warning 또는 #pragma는 전 처리기 지시문이므로 micah의 전 동료의 코드가 있는지 여부에 관계없이 실행되며 속성과 전혀 상호 작용하지 않습니다. Obsolete는 이것을 달성하는 유일한 방법입니다 ...
— 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!
}

그런 다음 메뉴에서보기 / 작업 목록을 엽니 다. 작업 목록에는 사용자 작업과 설명의 두 가지 범주가 있습니다. 댓글로 전환하면 // Todo :가 모두 표시됩니다. TODO를 두 번 클릭하면 코드의 주석으로 이동합니다.

Al


1
나는 이것이 더 바람직한 해결책이라고 생각한다
— Samuel

1
함수를 "생산 코드에서 호출되지 않음"또는 이와 유사한 것으로 표시하려면 어떻게해야합니까? 따라서 함수 나 클래스가 호출되거나 인스턴스화되면 실행되지만 컴파일 된 경우에는 실행되지 않습니다.
— 제시 페퍼

2

나는 당신이 할 수 있다고 생각하지 않습니다. 내가 아는 한 ObsoleteAttribute에 대한 지원은 기본적으로 C # 컴파일러에 하드 코딩됩니다. 당신은 직접적으로 비슷한 것을 할 수 없습니다.

수행 할 수있는 작업은 방금 컴파일 된 어셈블리에 대해 사용자 지정 도구를 실행하는 MSBuild 작업 (또는 빌드 후 이벤트)을 사용하는 것입니다. 사용자 지정 도구는 어셈블리의 모든 형식 / 메서드를 반영하고 사용자 지정 특성을 사용하여 System.Console의 기본값 또는 오류 TextWriter에 인쇄 할 수 있습니다.


2

ObsoleteAttribute 의 소스를 살펴보면 컴파일러 경고를 생성하기 위해 특별한 작업을 수행하지 않는 것처럼 보이므로 @ technophile 를 사용하여 컴파일러에 하드 코딩되었다고 말하는 경향이 있습니다. ObsoleteAttribute 를 사용하여 경고 메시지를 생성 하지 않으려는 이유가 있습니까?


코드 이외의 특별한 이유가 반드시 쓸모없는 것은 아닙니다.
— Micah

1
컴파일러에 의해 특별히 처리되는 것으로 C # 사양에 지정되어 있습니다. 내 대답을 확인하십시오 :-). Micah- 'Obsolete 속성은 더 이상 사용하지 않아야하는 유형과 유형의 구성원을 표시하는 데 사용됩니다.' 사양에서. 적용되지 않습니까? ...
— ljs

누군가 궁금한 점이 있다면 소스 코드에도이 작업을 수행 할 수있는 C # 코드가 없습니다. referencesource.microsoft.com/#mscorlib/system/…
— Paweł Mach

1

경고 또는 pragma 삽입을 제안하는 몇 가지 주석이 있습니다. 구식은 매우 다른 방식으로 작동합니다! 라이브러리 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.