Özel Derleyici Uyarıları


115

.Net'te ObsoleteAtribute kullanıldığında, size nesnenin / yöntemin / özelliğin eski olduğunu ve başka bir şeyin kullanılması gerektiğini söyleyen derleyici uyarıları verir. Şu anda eski bir çalışan kodunun yeniden düzenlenmesini gerektiren bir proje üzerinde çalışıyorum. Yazdığım mesajları veren derleyici uyarıları oluşturacak yöntemleri veya özellikleri işaretlemek için kullanabileceğim özel bir öznitelik yazmak istiyorum. Bunun gibi bir şey

[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

Bunun "Bu kod sux ve bakılması gereken" diyen bir derleyici uyarısı oluşturmasını istiyorum. Özel bir özniteliğin nasıl oluşturulacağını biliyorum, soru, görsel stüdyoda derleyici uyarıları oluşturmasına nasıl neden olabilirim.


Bu C # mi? Orijinal posterin seçmek istediği şeyin bu olduğu varsayımına dayanarak, bunu varsayımsal olarak C # (C değil) olarak yeniden etiketleyeceğim.
Onorio Catenacci

13
Bu geçerli bir VB veya C # değil ... öyleyse nedir ...?!
ljs

5
Eski soru, ancak şimdi Roslyn'i kullanarak özel derleyici uyarıları tanımlayabilirsiniz.
RJ Cuthbertson

4
@jrummell Roslyn dilinde, kod analizcileri: johnkoerner.com/csharp/creating-your-first-code-analyzer
RJ Cuthbertson

2
@RJCuthbertson Hak ettiği ilgiyi göstermek için yorumunuzu kabul edilen cevaba taşıdım.
jpaugh

Yanıtlar:


27

Güncelleme

Bu artık Roslyn (Visual Studio 2015) ile mümkündür. Sen edebilirsiniz inşa bir kod analizörü özel ayrıntı olmadığını kontrol etmek için


Bunun mümkün olduğuna inanmıyorum. ObsoleteAttribute, derleyici tarafından özel olarak ele alınır ve C # standardında tanımlanır. ObsoleteAttribute neden kabul edilemez? Bana öyle geliyor ki, tam da bunun için tasarlandığı durum bu ve tam olarak ihtiyacınız olanı sağlıyor!

Ayrıca, Visual Studio'nun ObsoleteAttribute tarafından oluşturulan uyarıları da anında aldığını unutmayın, bu çok yararlıdır.

Yararsız olmak istemeyin, sadece neden kullanmaya istekli olmadığınızı merak ediyorum ...

Maalesef ObsoleteAttribute mühürlenmiştir (muhtemelen kısmen özel muameleden dolayı), bu nedenle kendi niteliğinizi ondan alt sınıflara alamazsınız.

C # standardından: -

Obsolete niteliği, artık kullanılmaması gereken türlerin ve türlerin üyelerini işaretlemek için kullanılır.

Bir program, Obsolete özniteliğiyle dekore edilmiş bir tür veya üye kullanırsa, derleyici bir uyarı veya hata verir. Özellikle, derleyici, hata parametresi sağlanmazsa veya hata parametresi sağlanırsa ve false değerine sahipse bir uyarı verir. Hata parametresi belirtilirse ve true değerine sahipse derleyici bir hata verir.

Bu, ihtiyaçlarınızı özetlemiyor mu? ... düşünmediğimden daha iyisini yapamayacaksınız.


14
Ben de aynı şeyi arıyorum. Kullanılmayan 'çalışır' ancak kod, yeniden düzenleme nedeniyle eksik olduğu kadar eski değildir.
g.

11
@G'ye ve muhtemelen orijinal yazara katılıyorum. Eski, eski anlamına gelir, kullanmayın. Bir şeyi "hey bu derlemeler, ancak gerçekten a) işlevselliği tamamlamamız veya b) yeniden düzenleyicimiz" olarak işaretlemek istiyorum. Bu daha çok bir geliştirme zamanı niteliği olacaktır. Ayrıca görevler de çalışır, örneğin // YAPILACAKLAR: ama ben bunları kullanmıyorum, tahmin ettiğim gibi pek çok kişi kullanmıyor, derleyici uyarılarını düzenli olarak gözden geçiriyorum.
MikeJansen

8
[Obsolete]Etiketi kullanmamanın bir başka nedeni de , özellik ile XmlSerialization yapmanız gerektiğinde sorunlara neden olabilmesidir. [Obsolete]Etiketin eklenmesi, [XmlIgnore]arka planda öznitelik de ekler .
burnttoast11

6
Eski farklıdır. Eski, bu yöntemi çağıran her kod satırında size bir uyarı verecektir. Posterin istediği şeyin bu olduğunu sanmıyorum (en azından bir arama yaptığımda ve bu soruyu bulduğumda istediğim bu değil). Sorunun, işlevin kullanıldığı yerde değil, işlevin tanımında ortaya çıkacak bir uyarı olduğunu düşündüm.
Nick

En büyük cevap değil. -1, onu kullanmamak için bir sebep bulamamanızı düşünmek eleştiriye değer. Bu tutum, özgünlüğü caydırır.
Mike Socha III

96

Bu denemeye değer.

Artık Kullanılmayan'ı genişletemezsiniz, çünkü bu nihaidir, ancak belki kendi niteliğinizi oluşturabilir ve bu sınıfı şu şekilde eski olarak işaretleyebilirsiniz:

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

Daha sonra yöntemlerinizi "MustRefactor" özniteliğiyle işaretlediğinizde, derleme uyarıları görünecektir. Bir derleme zamanı uyarısı oluşturur, ancak hata mesajı komik görünüyor, bunu kendiniz görmeli ve seçmelisiniz. Bu, ulaşmak istediğiniz şeye çok yakın.

GÜNCELLEME: Bu kodla bir uyarı oluşturur (çok hoş değil ama daha iyi bir şey olduğunu düşünmüyorum).

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
{

}

Ürettiklerini yapıştırabilir misin? Merak ediyorum.
Micah

1
Özellik / Yöntem çağrılmasa bile derleme uyarısı tetiklenir.
Rolf Kristensen

1
Burada iyi öneriler. Ben de aynı şeyi yapmak istiyordum ve sonunda NotImplementedExceptions'ı atmaya başladım. Derleme zamanında görünmedikleri için en iyi çözüm değil, sadece kod çalıştırılacaksa çalışma zamanında. Bunu kendim deneyeceğim.
Monkeywrench

1
ObsolteAttribute, DebuggerDisplayAttribute gibi ifadeleri destekleseydi harika olmaz mıydı, o zaman gerçekten harika şeyler yapabilirdik. visualstudio.uservoice.com/forums/121579-visual-studio/…
jpierson

IDisposableBu eski sınıfları uygularsanız , tehlikeli test kodunuzu bir usingbloğa sarabileceğiniz anlamına gelir . Bunun gibi: using(new MustRefactor()){DodgyCode();}. O zaman işiniz bittiğinde tüm kullanımları bulabilirsiniz. Bunu şu anda Sleepbir for döngüsü içindeki iş parçacığı için kullanıyorum, hata ayıklama amacıyla yapay olarak yavaşlatmam gerekiyor.
Iain Fraser

48

Bazı derleyicilerde bir uyarı vermek için #warning kullanabilirsiniz:

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

Microsoft derleyicilerinde, tipik olarak mesaj pragmasını kullanabilirsiniz:

#pragma message ( "text" )

.Net'ten bahsettiniz, ancak C / C ++ veya C # ile programlama yapıp yapmadığınızı belirtmediniz. C # ile programlama yapıyorsanız, bilmeniz gerekenden daha C #, #warning biçimini destekler .


1
#warning veya #pragma, ön işlemci yönergeleridir ve bu nedenle, micah'ın eski meslektaşlarının kodlarından herhangi birinin varlığına bakılmaksızın çalışır ve öznitelikle hiç etkileşime girmez. Oldukça kesin Eski, bunu başarmanın tek yolu ...
ljs

39

Şu anda her şeyi hemen düzeltemediğimiz birçok yeniden düzenleme sürecinin ortasındayız. Geri dönüp koda bakmamız gereken yerde #warning preproc komutunu kullanıyoruz. Derleyici çıktısında görünür. Bunu bir yönteme koyabileceğinizi sanmıyorum, ancak onu yöntemin içine koyabilirsiniz ve bulması yine de kolaydır.

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

7

VS 2008'de (+ sp1) #warnings, Clean Soultion & Rebuild Solution'dan sonra Hata Listesinde düzgün görünmüyor, hepsi değil. Hata Listesinde bazı Uyarılar yalnızca belirli bir sınıf dosyasını açtıktan sonra gösteriliyor. Bu yüzden özel özniteliği kullanmak zorunda kaldım:

[Obsolete("Mapping ToDo")]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property)]
public class MappingToDo : System.Attribute
{
    public string Comment = "";

    public MappingToDo(string comment)
    {
        Comment = comment;
    }

    public MappingToDo()
    {}
}

Bu yüzden onunla bir kod işaretlediğimde

[MappingToDo("Some comment")]
public class MembershipHour : Entity
{
    // .....
}

Bunun gibi uyarılar üretir:

Namespace.MappingToDo artık kullanılmıyor: 'Yapılacaklar Eşleme'.

Uyarının metnini değiştiremiyorum, 'Bazı yorumlar' ona Hata Listesi gösterilmiyor. Ancak dosyada uygun yere atlayacaktır. Bu nedenle, bu tür uyarı mesajlarını değiştirmeniz gerekirse, çeşitli özellikler oluşturun.


6

Yapmaya çalıştığınız şey, niteliklerin kötüye kullanılmasıdır. Bunun yerine Visual Studio Görev Listesi'ni kullanın. Kodunuza şöyle bir yorum girebilirsiniz:

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

Ardından menüden Görünüm / Görev Listesini açın. Görev listesinin iki kategorisi vardır, kullanıcı görevleri ve Yorumlar. Yorumlara geç ve // ​​Yapılacakların hepsini orada göreceksin. TODO'ya çift tıklamak kodunuzdaki yoruma atlayacaktır.

Al


1
Bunu daha tercih edilen bir çözüm buluyorum
Samuel

1
Ya bir işlevi "Üretim kodunda çağrılmayacak" veya benzeri olarak işaretlemek isterseniz. Dolayısıyla, bir işlev veya sınıf çağrıldığında veya başlatıldığında ateşlenmesini istersiniz, ancak henüz derlenmişse değil.
Jesse Pepper

2

Yapabileceğini sanmıyorum. Bildiğim kadarıyla, ObsoleteAttribute desteği esasen C # derleyicisine kodlanmıştır; doğrudan benzer bir şey yapamazsınız.

Yapabileceğiniz şey, henüz derlenmiş derlemeye karşı özel bir araç çalıştıran bir MSBuild görevi (veya bir derleme sonrası olayı) kullanmaktır. Özel araç, derlemedeki tüm türleri / yöntemleri yansıtır ve özel özniteliğinizi kullanır, bu noktada System.Console'un varsayılan veya hatalı TextWriters'a yazdırabilir.


2

ObsoleteAttribute için kaynağa bakıldığında, bir derleyici uyarısı oluşturmak için özel bir şey yapıyormuş gibi görünmüyor, bu yüzden @ technophile ile gitme ve derleyiciye kodlanmış olduğunu söyleme eğilimindeyim . Uyarı mesajlarınızı oluşturmak için ObsoleteAttribute kullanmak istememenizin bir nedeni var mı ?


Kod dışında belirli bir neden mutlaka eski değildir.
Micah

1
C # belirtiminde derleyici tarafından özel olarak ele alınacak şekilde belirtilmiştir, cevabıma bakın :-). Micah - 'Artık kullanılmaması gereken türlerin türlerini ve üyelerini işaretlemek için Kullanılmayan özniteliği kullanılır.' şartnameden. Bu uygulanabilir değil mi? ...
ljs

Biri merak ettiyse, bunu yapacak kaynak kodda C # kodu da yok. reference.microsoft.com/#mscorlib/system/…
Paweł Mach

1

Uyarı veya pragma eklemeyi öneren birkaç yorum vardır. Eski, çok farklı bir şekilde çalışır! Bir kütüphane L'nin eski bir fonksiyonu olarak işaretlendiğinde, eski mesaj, çağıran program L kütüphanesinde olmasa bile bir program fonksiyonu çağırdığında yükselir. Uyarı mesajı SADECE L derlendiğinde yükseltir.


1

İşte Roslyn Uygulaması, böylece anında uyarılar veya hatalar veren kendi özniteliklerinizi oluşturabilirsiniz.

IdeMessageUyarıları oluşturan öznitelik olacak bir Type Called özniteliği oluşturdum:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
public class IDEMessageAttribute : Attribute
{
    public string Message;

    public IDEMessageAttribute(string message);
}

Bunu yapmak için önce Roslyn SDK'yı kurmanız ve analizör ile yeni bir VSIX projesi başlatmanız gerekir. Mesajlar gibi daha az alakalı bazı kısımları atladım, bunu nasıl yapacağınızı anlayabilirsiniz. Analiz cihazınızda bunu yaparsınız

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);
}

Bunun için CodeFixProvider yok, çözümden kaldırabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.