Obsolete member field with property accessor (Visual Studio bug) - c#

I have a class with a member that I need to keep for legacy code and I need to mark it as obsolete so that new code doesn't use it (without getting a warning).
Let's say the class looks like this:
class MyClass
{
[Obsolete]
private string _old = "...";
[Obsolete]
public string Old
{
get { return _old; }
}
}
I'm declaring that the member field _old is obsolete to make sure that new code inside the class do not use that field.
I'm also declaring that the property Old is obsolete to make sure that code outside of the class do not use the property.
When I compile this I get a warning in the property getter saying that _old is obsolete. I thought that the compiler would silently ignore this since the property itself is obsolete.
Am I missing something or do I need to add #pragma warning disable/restore for obsolete member fields everywhere they're used (even though the method/property itself is marked as obsolete)?
The reason that "I thought that the compiler would silently ignore this" is because it seems to do so for obsolete classes:
[Obsolete]
public class MyObsoleteClass
{
public string DoSomething()
{
// No warning here, since the class itself is obsolete
return new MyClass().Old;
}
}
As #Heinzi answered: this seems to be due to a bug in Visual Studio. I've filed a report on connect:
https://connect.microsoft.com/VisualStudio/feedback/details/1146809
It turns out that the bug in Visual Studio is not just limited to accessing an obsolete field from a property.
Accessing an obsolete property from an obsolete method should not yield a warning:
public class Class2
{
[Obsolete]
public string Property { get; set; }
[Obsolete]
public void Method()
{
this.Property = "value"; // <-- Incorrect warning reported
}
}
Neither should doing so from another class:
public class Class3
{
[Obsolete]
public string Property { get; set; }
}
public class Class4
{
[Obsolete]
public string Method()
{
return new Class3().Property; // <-- Incorrect warning reported
}
}
Interestingly, it works in the following class and when adding this class the other warnings (from Class4 and Class2) will magically disappear.
public class Class5
{
[Obsolete]
public void Method()
{
// No warning reported here, which is good.
// This magically makes the other warnings disappear too!
new Class2().Method();
}
}

Your code is fine, and your understanding of how the Obsolete attribute should work is correct: If you look at the "Output" tab after compilation, you will note that the compiler does not output a warning for your case (but will output a warning if you remove the Obsolete attribute from your property, as expected).
You are right, though, that Visual Studio sometimes displays a warning after making arbitrary changes to the code. This seems to be a bug in Visual Studio. If you can still reproduce it with the most current version, I would suggest that you file a bug report on http://connect.microsoft.com.

This would be a clever feature, but I don't see any indication in the documentation that it should work this way. On the other hand I would not use the Obsolate attribute on a private member (if the class is not extremly huge), but I would refactor it instead. I your case I would write this:
class MyClass
{
[Obsolete]
public string Old
{
get; private set;
}
}
And then you only need to change the usages of _old to Old and the problem is solved.

Related

Raising warnings based on class attributes

Here is some code:
class Program
{
static void Main(string[] args)
{
MyClass class1 = new MyClass();
MyOtherClass class2 = new MyOtherClass();
Helper.UseAttribute<MyClass>(class1);
//Raise a warning to tell the developer that they cannot use this class
//as there is no property with the specified attribute.
Helper.UseAttribute<MyOtherClass>(class2);
}
}
public class MyAttribute : System.Attribute { }
class MyClass
{
[MyAttribute]
public string SomethingAwesome { get; set; }
}
class MyOtherClass
{
public string SomethingElseWhichIsAlsoPrettyAwesome { get; set; }
}
static class Helper
{
public static void UseAttribute<T>(T sender)
{
//Do something with the property that has MyAttribute
//If there isn't a property with this attribute, then raise
//a warning.
}
}
In an ideal scenario, I want to restrict a developer from passing classes to a method which do not have a certain attribute.
I am aware that I can use an interface, or a base class of some description, however the question really is whether something like the example above is possible.
If you're happy to either use the VS 2015 preview or wait until VS 2015 is out, you can use Roslyn for this.
You'd write a DiagnosticAnalyzer class, probably registering a syntax node analyzer to specifically look for invocations of Helper.UseAttribute<T>. When you find such a use, you'd find the symbol for T and check whether there are any properties with the MyAttribute attribute applied to it, and raise a warning if not. This warning will be shown in Visual Studio itself, as well as applying on CI builds (assuming you register the analyzer assembly appropriately).
It takes a while to get started with the Roslyn diagnostic APIs, but once you're used to it, it's really powerful.
Of course, another option is to throw an exception at execution time, and rely on there being unit tests around all callers so that you'd be able to catch it when they fail :) You should probably do that as well as adding compile-time support via Roslyn.
Best you can do right now is to handle it on runtime (and throw an exception or something). On design-/compiletime I think there is no possibility yet.
public static void UseAttribute<T>(T sender)
{
var hasAttribute = typeof(T).GetProperties().Any(prop => Attribute.IsDefined(prop, typeof(MyAttribute)));
if (!hasAttribute)
throw new Exception("Does not contain attribute");
}

False CA1812 warning : "internal class that is apparently never instantiated..."

I am getting a code analysis warning that seems to be a false-positive.
CA1812 : Microsoft.Performance : 'MyClass.MyPrivateClass' is an internal class that is apparently never instantiated. If so, remove the code from the assembly. If this class is intended to contain only static methods, consider adding a private constructor to prevent the compiler from generating a default constructor.
How do I get rid of this warning? I prefer to not suppress warnings unless I am sure I couldn't avoid it otherwise.
The classes look like this:
namespace Some.Namespace
{
public class MyClass
{
private class MyPrivateClass
{
public int Id { get; set; }
public ModelObject { get; set; }
}
}
}
I use it like this:
private IQueryable<MyPrivateClass> GetMyPrivateClasses()
{
return this.Repository().All()
.Select(m => new MyPrivateClass { Id = m.Id, ModelObject = m };
}
Does this usage not count as instantiation?
I guess it is examining the IL; and genuinely - that IL does not ever contain a new MyPrivateClass instruction - because that statement is presumably running against IQueryable<T>, hence that lambda is an expression tree. It will contain some Expression.New, and some typeof(MyPrivateClass) - but no new MyPrivateClass.
In this case, the error is misleading. Simply suppress it.
FYI there is a new documentation page for this warning:
https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1812
Instantiation of classes is not always recognized by analyzers.
Suppress this warning, if justified:
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "generic/late bound/reflection")]
Happens especially in Net.Core.
Change your class to internal or public, that solves the problem. Anyway, you can extract your inner class from the outer class...

Attribute to generate compilerwarning for a method in class

I have a class, where I use the singleton-pattern. The class looks like
public class MessageAccess
{
private static MessageAccess instance;
public static MessageAccess Instance
{
get { return instance ?? (instance = new MessageAccess()); }
}
private MessageAccess()
{
}
public void Initialize(string data)
{
//...
isInitialized = true;
}
private bool isInitialized;
public void ReadData1()
{
// This Method can always be called
}
public void ReadData2()
{
// This Method can only be called, if Initialize was called. Otherwise an exception will be thrown
}
}
Is it possible to generate a compiler-warning if the Method Initialize is never called
While I understand your point of view, I don't think such warning would be as handy as you think. I'm afraid .NET framework doesn't cater for this type of warnings for a couple of well defined reasons (please refer to this link: http://blogs.msdn.com/b/csharpfaq/archive/2004/03/19/why-doesn-t-c-warn-about-unused-methods.aspx).
One might think that the lack of this feature is a missed opportunity, but it's not quite the case. Your class, MessageAccess, is public and will be compiled into (let's say) a dll. Even if you had this warning while compiling your dll, you wouldn't want it to appear while compiling some external code using that dll's Initialize method (which is also public). You basically can't guarantee that no other code will ever use that method, and this is one of the better reasons not to have this warning.
If the class is not used from outside the assembly, you can make it internal. In this case, Code Analysis will generate a warning "Avoid uncalled private code", if the method is not called.

CodeContracts Invariant is false

VS2010 keeps telling me that a CodeContract.Invariant is false. I can't see how this can possibly be the case
public class BankAccountIdentifierDefinitionVariation_CreateCommandArgs : ValidatedCommandArgs
{
public string IdentifierCode {get; private set; }
public string CountryCode {get; private set; }
public Ems.Infrastructure.Validation.StringValidator Validator {get; private set; }
private BankAccountIdentifierDefinitionVariation_CreateCommandArgs()
: base() { }
public BankAccountIdentifierDefinitionVariation_CreateCommandArgs(
string identifierCode,
string countryCode,
Ems.Infrastructure.Validation.StringValidator validator)
{
Contract.Requires(!string.IsNullOrEmpty(identifierCode));
Contract.Requires(!string.IsNullOrEmpty(countryCode));
Contract.Ensures(!string.IsNullOrEmpty(this.IdentifierCode));
Contract.Ensures(!string.IsNullOrEmpty(this.CountryCode));
this.IdentifierCode = identifierCode;
this.CountryCode = countryCode;
}
[ContractInvariantMethod]
void ContractInvariants()
{
Contract.Invariant(!string.IsNullOrEmpty(IdentifierCode));
Contract.Invariant(!string.IsNullOrEmpty(CountryCode));
}
}
The warning is that both invariants are false, which obviously cannot be the case. I have also tried the two following variations.
Contract.Ensures(!string.IsNullOrEmpty(this.IdentifierCode);
if (string.IsNullOrEmpty(identifierCode)) throw new ArgumentNullException...
this.IdentifierCode = identifierCode;
and also
Contract.Ensures(!string.IsNullOrEmpty(this.IdentifierCode));
this.IdentifierCode = identifierCode;
if (string.IsNullOrEmpty(this.IdentifierCode)) throw new ArgumentNullException...
It looks as if the invariant is false because it is possible for me to change the value of the property via its private setter (even though I do not.) Is there a way to deal with this? The properties must remain properties because I am serializing.
It seems that the static analyzer fails to see that the parameterless constructor is never invoked. Maybe its existance is enough to question your invariant.
Can you remove it altogether? If you already have a constructor, why do you need a private parameterless one?
I would expect the private default constructor to be the source of the warning, since executing that would indeed violate the invariant. However since you have a constructor defined there's nothing stopping you from deleting the default constructor. If you define at least one constructor the compiler will not emit a default contructor on your behalf and since you are never using the default constructor there's no reason to have it in the first place

Prevent Resharper "Possible Null Reference Exception" warnings

Let's say I have an interface with a read-only property and and a concrete class where the property is instantiated in the constructor and marked as read-only.
internal interface IExample
{
ObservableCollection<string> Items { get; }
}
internal class Example : IExample
{
private readonly ObservableCollection<string> _items;
public Example()
{
_items = new ObservableCollection<string>();
}
public ObservableCollection<string> Items
{
get { return _items; }
}
}
When I use the interface Resharper warns me that I might have a possible null reference in calling code.
public class ExampleWithWarnings
{
public void Show()
{
IExample example = new Example();
// resharper warns about null reference
example.Items.Add( "test" );
}
}
I realize that by definition the interface doesn't guarantee that the property will have a value. (I also recognize that properties on interfaces aren't ideal). But I know this property will always have a value.
Is there any magic attribute that I can put on the interface that would prevent Resharper from showing a warning? I'd rather not have to decorate all usages of the class with a disable pragma warning.
Yes, there is an attribute you can use: JetBrains.Annotations.NotNullAttribute. But you don't need to add a reference to ReSharper in your project. You can use your own implementation: open the ReSharper options, and under Code Inspection > Code Annotations you will find a "Copy default implementation to clipboard". Now just paste that into a code file in your project. You can even change the namespace.
And then slap the attribute in the interface property.
You should also have a look under Code Inspection > Settings and pick "Assume entity can be null... when entity is explictly marked with CanBeNull attribute, or checked for null". This way you only get warnings in the members you explicit mark as troublesome.
You can reduce this warning to a suggestion. You could also edit the external annotation files to create custom rules or behavior: http://msmvps.com/blogs/peterritchie/archive/2008/07/21/working-with-resharper-s-external-annotation-xml-files.aspx

Categories