I have a lot of classes that share a lot of properites and have a lot of common interfaces.
It happens very regularly that i want to construct an object with data from another object and they share an interface. To make that more easy i have this neat little method:
public static List<PropertyInfo> InterfaceProperties(Type type)
{
return new[] {type}
.Concat(type.GetInterfaces())
.SelectMany(i => i.GetProperties(BindingFlags.Instance | BindingFlags.Public)).ToList();
}
public static void SetFromSimilar<TInterface>(TInterface destination,TInterface source)
{
var properties = InterfaceProperties(typeof(TInterface));
foreach (var property in properties)
{
var val = property.GetValue(source, null);
property.SetValue(destination, val, null);
}
}
It works fantastic because now i can do this:
public class MyClass: IMyInterface
{
public MyClass(IMyInterface otherClass)
{
SetFromSimilar(this,otherClass)
}
....MyProperties.....
}
Now rider complains about non-nullable properties being uninitialized which makes sense. I know they are initialized but for the IDE thats hard to see and i get compilerwarnings. This throws me off because i see it marked as a potentialy error and i have to think everytime if there is something wrong.
Is there a substitute for my method where this will not happen?
Ok i got no answers so far. Is it not possible? Is this not a normal usecase? Is it somehow possible with net5?
The compiler warning:
C:\My\File\Path\MyClass.cs(10,16): warning CS8618: Non-Nullable-Eigenschaft "MyProperty" muss beim Beenden des Konstruktors einen Wert ungleich NULL enthalten.
Erwägen Sie eine Deklaration von "Eigenschaft" als Nullable. [C:\My\File\Path\MyProject.csproj]
It tells me to maybe make the property nullable which i absolutely don`t want.
The compiler and analyzers cannot usually (or easily) interpret reflection code, so it is quite reasonably unconvinced as to their assignment and nullability. If you know something is correct that the compiler can't verify: just add a suppression for the warning over that particular code block, via #pragma, a [SuppressMessage(...)] on the affected code, or a suppression file (which is just [assembly:SuppressMessage(...)] in a different file, with a Target to tell the compiler what it applies to). Rider may have some other ways of suppressing messages, via the context menu.
Note: if you go this route, you may also want to add assertions - especially in a DEBUG build - that what you belive to be true: is actually true.
If you're using C# 9, you could add a smattering of dammit (!) markers, or turn off nullability checking for that code.
Well yea, this does not look like a perfectly elegant solution to your problem, in my opinion. Here's some solutions I can think of, in order of elegance:
1. Quick & Brute force
Just tell rider to not complain about it with a #pragma statement, I believe in your case it should be this:
#pragma warning disable CS8618
[code that throws the warning]
#pragma warning restore CS8618
2. Write code to generate code
Write yourself a small application that extracts those common interfaces to autogenerate set-value code for each
3. Don't mix data with control code
If you need to set data on classes with different controllers, i.e. classes, put it into its own data class. Tadaaa, you just gained the ability of class inheritance for setting common values.
Related
Here is a piece of code:
IUser user = managerUser.GetUserById(UserId);
if ( user==null )
throw new Exception(...);
Quote quote = new Quote(user.FullName, user.Email);
Everything is fine here. But if I replace "if" line with the following one:
ComponentException<MyUserManagerException>.FailIfTrue(user == null, "Can't find user with Id=" + UserId);
where function implementation is following:
public abstract class ComponentException<T> : ComponentException
where T : ComponentException, new()
{
public static void FailIfTrue(bool expression, string message)
{
if (expression)
{
T t = new T();
t.SetErrorMessage(message);
throw t;
}
}
//...
}
Then ReSharper generates me a warning: Possible 'System.NullReferenceException' pointing on 1st usage of 'user' object.
Q1. Why it generates such exception? As far as I see if user==null then exception will be generated and execution will never reach the usage point.
Q2. How to remove that warning? Please note:
1. I don't want to suppress this warning with comments (I will have a lot of similar pieces and don't want to transform my source code in 'commented garbage);
2. I don't want to changes ReSharper settings to change this problem from warning to 'suggestion' of 'hint'.
Thanks.
Any thoughts are welcome!
P.S. I am using resharper 5.1, MVSV 2008, C#
Resharper only looks at the current method for its analysis, and does not recursively analyse other methods you call.
You can however direct Resharper a bit and give it meta-information about certain methods. It knows for example about "Assert.IsNotNull(a)", and will take that information into account for the analysis. It is possible to make an external annotations file for Resharper and give it extra information about a certain library to make its analysis better. Maybe this might offer a way to solve your problem.
More information can be found here.
An example showing how it's used for the library Microsoft.Contracts can be found here.
A new answer in old post...
Here a little sample of my code regarding how to use CodeContract via ContractAnnotation with Resharper:
[ContractAnnotation("value:null=>true")]
public static bool IsNullOrEmpty(this string value)
{
return string.IsNullOrEmpty(value);
}
It is very simple...if u find the breadcrumb in the wood. You can check other cases too.
Have a nice day
Q1: Because Resharper doesn't do path analysing. It just sees a possible null reference and flags that.
Q2: You can't without doing either of what you provided already.
You do know (or expect) that this code will throw an exception if there is a null reference:
ComponentException<MyUserManagerException>.FailIfTrue([...]);
However, since there is no contract specifying this, ReSharper has to assume that this is just a normal method call which may return without throwing any exception in any case.
Make this method implement the ReSharper contract, or as a simple workaround (which only affects debug mode, therefore no performance penalty for release mode), just after the FailIfTrue call:
Debug.Assert(user != null);
That will get rid of the warning, and as an added bonus do a runtime check in debug mode to ensure that the condition assumed by you after calling FailIfTrue is indeed met.
This is caused by the Resharper engine. These "possible NullReferenceException" happen because someone (probably at Resharper) has declared/configured somewhere an annotation on the method.
Here is how it works: ReSharper NullReferenceException Analysis and Its Contracts
Unfortunately, sometimes, these useful annotation are just wrong.
When you detect an error, you should report it to JetBrains and they will update the annotations on the next release. They're used to this.
Meanwhile, you can try to fix it by yourself. Read the article for more :)
Please check if you have any user==null if check above the given code. If there is, then ReSharper thinks that the variable "can be null" so recommends you to use a check/assert before referencing it. In some cases, that's the only way ReSharper can guess whether a variable can or cannot be null.
I'm making an extension to Visual Studio. Within the code I'm using Code Contracts to make assertions and checks. I set the warning option level to high.
What I would like to do is maintain that warning level while ignoring any checks made on EnvDTE references.
Consider the following code example:
public static string GetAbsoluteOutputFolder(EnvDTE.Project project)
{
if (project == null) throw new ArgumentNullException("project");
var path =
project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath").Value.ToString();
//...
}
With my current settings, CC would require me to add the following checks before assigning the path variable:
Contract.Assume(project.ConfigurationManager != null);
Contract.Assume(project.ConfigurationManager.ActiveConfiguration != null);
Contract.Assume(project.ConfigurationManager.ActiveConfiguration.Properties != null);
Therefore what I'd like to do here is to tell CC to "trust" EnvDTE and ignore these types and their properties.
I thought the "Be optimistic on external API" CC option served this very purpose; turns out it doesn't.
Is there a way to make it behave the way I want that would not require a lower warning level?
EDIT: I want a solution that would work at project level and that would still allow "regular" checks to be performed.
Can´t provide a detailed solution but this should be solvable by using either the Baseline Feature or System.Diagnostics.CodeAnalysis.SuppressMessage on assembly level:
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Contracts", "Whatever")]
You can use the "Target" Property of the SuppressMessageAttribute to only ignore the Message on specific Types / Methods / Namespaces:
[SuppressMessage("Microsoft.Contracts",
"CC1055",
Scope="Member",
Target="YouNamespace.EnvDTE.Project")]
Note that the Parameters i used are just a good bet, you´ll have to figure out the correct Scope, MessageId and Target yourself :) On a sidenote, i think the Attribute is Conditional("CODE_ANALYSIS").
The official suggested solution to this problem is to create some sort of wrapper, in your case probably a repository that would create or contain your EnvDTE.Project objects. Then you can add the required Contract.Ensures there.
I don't think it's possible to solve the problem but since C# 6.0 there is a workaround which at least eases the pain a bit:
Instead of
Contract.Assume(project.ConfigurationManager != null);
Contract.Assume(project.ConfigurationManager.ActiveConfiguration != null);
Contract.Assume(project.ConfigurationManager.ActiveConfiguration.Properties != null);
you can now write
Contract.Assume(project.ConfigurationManager?.ActiveConfiguration?.Properties != null);
Have you tried something with :
[assembly: Contracts.ContractVerification(false)] at the assembly level ?
You should be able to do it dynamically : https://msdn.microsoft.com/en-us/library/bb458043.aspx
Hope this helps,
Is there a way to force the use of the this keyword in Visual Studio when referencing current instance members?
Example with a bug in the constructor:
class MyClass
{
public object Foo { get; set; }
public MyClass(object foo)
{
Foo = Foo; // this should of course be lowercase but it's easy to miss
}
}
This code will probably generate the infamous 'object reference not set to an instance of an object' exception somewhere later on.
How to make it work but still It's easy to miss:
class MyClass
{
public object Foo { get; set; }
public MyClass(object foo)
{
Foo = foo; // Valid syntax but unclear.
}
}
This is valid syntax but it's easy to miss.
The syntax I'd like visual studio enforce:
class MyClass
{
public object Foo { get; set; }
public MyClass(object foo)
{
this.Foo = foo; // this is "safe".
}
}
If this convention is enforced i would have to type this.Foo = this.Foo to create the same type of bug as in the first example.
I always use the this keyword anyway since it makes my life easier while switching between c# and other languages so there wouldn't be any disadvantages at all.
You can fix this simply by enabling "Treat warnings as errors":
Warning 2 Assignment made to same variable; did you mean to assign something else?
(CS1717 if you want to enable it just for this one)
The compiler already tells you about this; you should be reviewing the warnings (and aim for zero warnings).
Re the middle one being unclear:
Foo = foo;
I disagree - that is perfectly clear to me (unless you come from a VB background and have developed case-blindness).
No, you can't change the behaviour of the language like this. If you use ReSharper I believe you can tell it to flag up this sort of thing - it may not come up in the error list, but in the margin and in an "indicator light" for the overall file health.
I personally don't tend to lose too much sleep over this sort of thing, as it's usually obvious as soon as you test - I can only recall one scenario where it's really bitten me, which was when I ended up with a stack overflow (not exactly the same situation, but again a casing issue) within a type initializer, running on Windows Phone 7 - a mixture of difficult debug environments, basically.
You can use StyleCop to generate a warning if you do not prefix with this. You can get StyleCop to run as part of the build process by following these these instructions
StyleCop comes with a bunch of default rules, many of them terrible, but you can edit your rules file to make the most sense for your developers. You can also share the StyleCop file so changes are immediately replicated to all your developers.
Its a fairly nice solution, free, provided by Microsoft and if you come up with a suitable rule set then your developers will create much "neater" code. You can also create custom rules along the lines of "Methods shouldn't be too long" where you define the length. Plenty of things to play with.
Also I guess you could set warnings as errors, but if you do make sure your StyleCop settings are exactly as you want them.
You can create custom warnings and errors using FXCop\Visual Studio Code Analysis
You can use StyleCopAnalyzers, rule SA1101:
Cause:
A call to an instance member of the local class or a base class is not prefixed with 'this.', within a C# code file.
Then you can right click the rule in solution explorer and set it to error, now it will not compile if "this" is not used.
I have a HTTPSystemDefinitions.cs file in C# project which basically describes the older windows ISAPI for consumption by managed code.
This includes the complete set of Structures relevant to the ISAPI not all or which are consumed by code. On compilation all the field members of these structures are causing a warning like the following:-
Warning Field 'UnionSquare.ISAPI.HTTP_FILTER_PREPROC_HEADERS.SetHeader' is never assigned to, and will always have its default value null
or
Warning The field 'UnionSquare.ISAPI.HTTP_FILTER_PREPROC_HEADERS.HttpStatus' is never used
Can these be disabled with #pragma warning disable? If so what would the corresponding error numbers be? If not is there anything else I can do? Bear in mind that I only what to do this for this file, its important that I get see warnings like these coming from other files.
Edit
Example struct:-
struct HTTP_FILTER_PREPROC_HEADERS
{
//
// For SF_NOTIFY_PREPROC_HEADERS, retrieves the specified header value.
// Header names should include the trailing ':'. The special values
// 'method', 'url' and 'version' can be used to retrieve the individual
// portions of the request line
//
internal GetHeaderDelegate GetHeader;
internal SetHeaderDelegate SetHeader;
internal AddHeaderDelegate AddHeader;
UInt32 HttpStatus; // New in 4.0, status for SEND_RESPONSE
UInt32 dwReserved; // New in 4.0
}
Yes, these can be suppressed.
Normally, I'm opposed to suppressing warnings, but in this case, structs used for interop absolutely requires some fields to be present, even though you never intend to (or can) use them, so in this case I think it should be justified.
Normally, to suppress those two warnings, you would fix the offending code. The first ("... is never used") is usually a code-smell of leftovers from earlier versions of the code. Perhaps code was deleted, but fields left behind.
The second is usually a code-smell for incorrectly used fields. For instance, you might incorrectly write the new value of a property back to the property itself, never writing to the backing field.
To suppress warnings for "Field XYZ is never used", you do this:
#pragma warning disable 0169
... field declaration
#pragma warning restore 0169
To suppress warnings for "Field XYZ is never assigned to, and will always have its default value XX", you do this:
#pragma warning disable 0649
... field declaration
#pragma warning restore 0649
To find such warning numbers yourself (ie. how did I know to use 0169 and 0649), you do this:
Compile the code as normal, this will add some warnings to your error list in Visual Studio
Switch to the Output window, and the Build output, and hunt for the same warnings
Copy the 4-digit warning code from the relevant message, which should look like this:
C:\Dev\VS.NET\ConsoleApplication19\ConsoleApplication19\Program.cs(10,28):
warning CS0649: Field 'ConsoleApplication19.Program.dwReserved' is never
assigned to, and will always have its default value 0
Caveat: As per the comment by #Jon Hanna, perhaps a few warnings is in order for this, for future finders of this question and answer.
First, and foremost, the act of suppressing a warning is akin to swallowing pills for headache. Sure, it might be the right thing to do sometimes, but it's not a catch-all solution. Sometimes, a headache is a real symptom that you shouldn't mask, same with warnings. It is always best to try to treat the warnings by fixing their cause, instead of just blindly removing them from the build output.
Having said that, if you need to suppress a warning, follow the pattern I laid out above. The first code line, #pragma warning disable XYZK, disables the warning for the rest of that file, or at least until a corresponding #pragma warning restore XYZK is found. Minimize the number of lines you disable these warnings on. The pattern above disables the warning for just one line.
Also, as Jon mentions, a comment as to why you're doing this is a good idea. Disabling a warning is definitely a code-smell when done without cause, and a comment will prevent future maintainers from spending time either wondering why you did it, or even by removing it and trying to fix the warnings.
Another "solution" to fix these warnings is by making the struct public. The warnings are not issued then because the compiler can't know whether or not the fields are being used (assigned) outside of the assembly.
That said, "interop" components should usually not be public, but rather internal or private.
I got VS to generate the implementation skeleton for System.ComponentModel.INotifyPropertyChanged and the events were implemented as fields which triggered the CS0067 warnings.
As an alternative to the solution given in the accepted answer I converted the fields into properties and the warning disappeared.
This makes sense since the property declarations syntax sugar are compiled into a field plus getter and/or setter methods (add/remove in my case) which reference the field. This satisfies the compiler and the warnings are not raised:
struct HTTP_FILTER_PREPROC_HEADERS
{
//
// For SF_NOTIFY_PREPROC_HEADERS, retrieves the specified header value.
// Header names should include the trailing ':'. The special values
// 'method', 'url' and 'version' can be used to retrieve the individual
// portions of the request line
//
internal GetHeaderDelegate GetHeader {get;set;}
internal SetHeaderDelegate SetHeader { get; set; }
internal AddHeaderDelegate AddHeader { get; set; }
UInt32 HttpStatus { get; set; } // New in 4.0, status for SEND_RESPONSE
UInt32 dwReserved { get; set; } // New in 4.0
}
C/C++ users have (void)var; to suppress unused variables warnings.
#Pang in the comments reports that the variable discards can be used for warnings suppression:
_ = variable;
This is probably available since C# 7.0, that introduce such use of underscore in the language syntax. In previous versions of the language once could suppress unused variables warnings in C# with bitwise operators, for types where such operators are defined:
uint test1 = 12345;
test1 |= 0; // test1 is still 12345
bool test2 = true;
test2 &= false; // test2 is now false
Using such strategy is certainly fishy and to use as last resort. Better to upgrade language support and use variable discard syntax.
I have an enumeration value marked with the following attribute. The second parameter instructs the compiler to error whenever the value is used. I want this behavior for anyone that implements my library, but I need to use this enumeration value within my library. How do I tell the compiler to ignore the Obsolete error for the couple of uses in my library.
public enum Choices
{
One,
Two,
[ObsoleteAttribute("don't use me", true)]
Three,
Four
}
Solution (Thanks everyone)
public class EnumHack
{
static EnumHack()
{
// Safety check
if (Choices!= (Choices)Enum.Parse(typeof(Choices), "Three"))
throw new Exception("Choices.Three != 3; Who changed my Enum!");
}
[Obsolete("Backwards compatible Choices.Three", false)]
public const Choices ChoicesThree = (Choices)3;
}
Private a separate constant somewhere like this:
private const Choices BackwardsCompatibleThree = (Choices) 3;
Note that anyone else will be able to do the same thing.
What about using #pragma to disable the warning around the specfic code?
#pragma warning disable 0612
// Call obsolete type/enum member here
#pragma warning restore 0612
A note to visitors, this only works with types and enum members. As far as I am aware, this will not work with other type members (e.g. methods, properties, etc).
What I see is that you're using this public enum for private logic, and after obsoleting it, you still need that logic internally.
I see 2 options:
Map it to a private Enum when you use it for your branching logic. You should be able to straight cast from one to the other.
Cast it from an int, thus never using the actual Enum value in your code.
As Jon points out above, anyone using your library can, and WILL (I know where you work), just hack through it anyhow.
It may not be the prettiest solution in the world, but you can try to trick the compiler by assigning values to the enum and then casting on your internal calls. For example this app runs:
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
TestMethod((Choices)3);
}
private static int TestMethod(Choices choice) {
return 1;
}
}
public enum Choices
{
One = 1,
Two = 2,
[ObsoleteAttribute("don't use me", true)]
Three = 3,
Four = 4
}
}
I thought that Enum.Parse would work but it gets a run-time error, so don't do this:
(Choices)Enum.Parse(typeof(Choices), "Choices.Three")
I don't have experience with obsolete enums so I would recommend some pretty good testing around this.
TheSoftwareJedi correctly notes that this won't work with obsolete attribute set to be an error. The following "answer" only works when the obsolete notification is raised as a warning.
From Visual Studio you can do this on a per-project basis:
Go to the Project Properties page for the project you want to be able to suppress the obsolete warning on.
Go to the Build tab: Errors and Warnings : Suppress Warnings
Enter the warning number, 0612 in this case.
Other projects will continue to get the obsolete warning but this project will not. Note that this will disable ALL obsolete warnings.