사용자 정의 컴파일러 경고


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.