C# class backward compatibility - c#

I have a NuGet package that is been used by some projects internally. Now, while refactoring the project, I found several classes that were named inappropriately. I want to know if there is any way in C# change the class names and not break anything.

There is no way to rename identifiers without breaking other people code. The best thing you can do is to leave clAssNaME identifier, provide new ClassName and mark clAssNaME as deprecated. Publish new release with documented and highlighted changelog.
When you're confident enough that most people managed to fix their code, delete the clAssNaME.

What you do depends on the extent of the changes. If the types with the changed names are not simple types (ie. have a lot of behavior) or are used throughout your package it can be very difficult to create a copy of the type because you also have to ensure the code can use either type (for a while anyways).
A simpler solution might be to branch your package and increment the major version number in the new branch. In the "new" branch: Update the type names, document the breaking changes, and push a release as a new version. You can then maintain both branches until you see fit to stop work on the "older" branch. In the "older" branch you can also mark types as deprecated with a warning that in the future version they will have a changed name.

Related

Ignoring files from checkin with certain pattern of change

Since having started using JetBrains Annotations, for my own benefit I've decorated all methods with [CanBeNull] or [NotNull]
For example, the following line:
public AccountController(IAccountService accountService)
Would be changed to:
public AccountController([CanBeNull] IAccountService accountService)
Another example would be:
public Account CreateAccountEntity(Account accountEnttity)
would be changed to:
[CanBeNull]
public Account CreateAccountEntity([NotNull] Account accountEnttity)
How can I bypass pending changes for annotations, specifically "[CanBeNull]", and have TFS completely ignore this change?
You cannot make TFS "ignore" the change. That is the purpose of TFS - to track all changes.
The way I interpret your question, you are wanting to avoid the noise of potentially many small but innocuous checkins due to your annotations. If this is correct then there is a way to use TFS that will minimize the noise:
create a branch from where you are currently working (let's call it "BranchA"), then make all the annotation changes in that new branch ("BranchB"), checking them in regularly
if this is going to take some time (days, weeks) to complete then ensure you do regular merges from BranchA to BranchB
when you think you've finished do a final merge from BranchA to BranchB. If you've pulled across any new methods then ensure you annotate them. Repeat this step if you made changes.
merge all changes from BranchB back to BranchA. This will have the effect of aggregating all your smaller changes into a single large checkin/changeset in BranchA. Provided you have been doing regular merges from BranchA to BranchB this should be problem free even if considerable time has passed since you started the decoration work.
In short, you shouldn't, the closest feature is the tfignore, but this will ignore all file.
On the other hand, if you really want this, you could create a tool using the TFS API, and you would have to run this before check-ins and it would verify all the pending files in your solution and looking for this small changes and excluding the files, but this could cause the problem that at some point you may make a change to an excluded file and it won't get checked in and cause problems. You would need to add extra code to verify what files should be included from the excluded list.
External tool used inside VS Here you can see how to add tools to the Tools menu and send arguments to it.
TFS API Example
This example shows how to use the TFS API. There is a 'workspace.AddIgnoreFileExclusion()', but I don't have TFS here, so I'll verify how to ignore the files later.
Now in my experience, the only reason I wouldn't want to check in those changes would be to avoid conflicts with the team.
If I see a lot of value in some practice like using the annotations, I would talk with the team to get them to buy in into the idea of using annotations, that way everyone would be using it and soon every file will have the annotations and there won't be any conflicts.
You can't selectively ignore changes within files, in TFVC or in any other SCM I've ever encountered.
I agree with other answers that such kind of feature isn’t officially supported by Microsoft.
But you can also overwrite TFVC in a few ways if it is really needed. You can write your own Visual Studio plug-in or Source Control VSPackage .
If your main goal is to write better code with the help of ReSharper telling you whether you should expect nulls or not or produce other warnings and you don't want to disturb other team members with it I would suggest you to consider using External Annotations instead of annotation attributes in code.
You can then decide whether you want to commit those files or keep them locally. And even if you commit your code will still be clean without those extra attributes.
At least I would give it a try.

How to ignore reference to jetbrains.annotations.dll in NodaTime nuget package xml documentation file

I lean quite heavily on Resharper context actions to generate boilerplate code. The Check parameter for null context action had, up until recently, generated code that performs the null check and throws accordingly. However, now it is adding a Resharper specific [NotNull] annotation to the parameter as part of the method signature.
Looking at this related question Stop ReSharper from Adding Annotations, I've checked across my solution codebase for jetbrains.annotations.dll references but not found any.
However, searching across all files I've found references to jetbrains.annotations.dll in the xml documentation file for NodaTime (NodaTime.xml).
Specifically, entries like this:
<member name="T:JetBrains.Annotations.NotNullAttribute">.
Im not categorically stating that this is the root cause. However, NodaTime is the most recent nuget package I have added since the issue began, and a grep across the solution shows this to be the single point of reference.
Should xml documentation files be including these references, and if so, is there a way for me to configure Resharper to ignore them?
UPDATE
I've decompiled the NodaTime assembly and although it doesn't have any binary references to jetbrains.annotations.dll it does appear to (re)declare the offending JetBrains.Annotations namespaces and annotations within itself.
As per citizenmatts suggestion, Ive used the Resharper take me to definition tool for the [NotNull] attribute and this goes to the NodaTime.dll
I've also just noticed that the NotNull attributes Resharper is including do not compile and complain of Cannot reference internal class NotNullAttribute. Hence I obviously don't have the jetbrains.annotations.dll included anyway.
UPDATE 2
Just done the obvious thing of creating a new blank project in VS2013 and checking the null check context action in Resharper works. Then added NodaTime nuget package and rechecked - and indeed it adds the [NotNull] attribute and the project wont compile.
UPDATE 3
As suggested by Jon Skeet I've tried "turning off" data annotations using Resharper-->Code Inspection-->Code Annotations-->Unticking JetBrains.Annotations. However, this has no affect and the NotNull attribute continues to be included.
Looks like I may just have to return to System.DateTime.
Noda Time deliberately ships with an internal copy of the R# annotations, so that those who do want them can benefit from them - it will know which methods are pure, etc.
It sounds like you don't actually want to use annotations at all, so it's just worth disabling them. That's easy from the R# options - under Code Inspection / Code Annotations, uncheck the JetBrains.Annotations option.
We can certainly consider moving the annotations into a specific namespace for Noda Time in the future, so that it's more opt-in than opt-out, but this is probably a good solution if you don't want to use annotations, as it makes it absolutely clear to R# that you really don't want to use them, even if other libraries include annotations.
EDIT: Just to promote Matt's comment into this answer:
Sadly, this is a bug in ReSharper - it doesn't take visibility of the NotNullAttribute into account before applying it. Here's the ticket to track and vote on: http://youtrack.jetbrains.com/issue/RSRP-413425
NodaTime.dll ships with the JetBrains annotations compiled in as internal symbols, which means they're used internally to NodaTime and not visible for anyone else to use. However, ReSharper can see these annotations that have been applied to the NodaTime classes and methods.
NodaTime doesn't have any binary references to JetBrains.Annotations.dll, and neither ReSharper nor Visual Studio should be adding a reference to a dll based on xml documentation. If ReSharper is able to add a [NotNull] annotation to your code, the dll must be being referenced from somewhere. I'd suggest invoking ReSharper's "go to definition" on the [NotNull] and see where it takes you - it should show you where the annotations dll is being referenced from, and you should be able to remove it easily from there.
Update: As noted above, and in the other answers, the issue is a bug in ReSharper that doesn't check the accessibility of the attribute before applying it. Here's the YouTrack ticket to track and vote on: http://youtrack.jetbrains.com/issue/RSRP-413425

Separating Designers from Main Assembly

Background
I am converting the TreeViewAdv(TVA) project on SourceForge to vb.net. Thus far I have successfully converted the code, successfully built it, added a reference of the dll to a new project, added the control to the toolbox, added the control to a form, and modified the controls properties. I have also coded functionality into the form prior to building that accepted the Aga.Controls namespace.
The Problem
When I go to debug the application that I have placed the TVA control in, I get the error: ''Aga' is not declared. It may be inaccessible due to its protection level.' on all calls to that namespace. So, I researched this problem on SourceForge and there is a thread here: https://sourceforge.net/p/treeviewadv/discussion/568369/thread/005e61ef/ that discusses this issue. Supposedly somebody figured out what the problem is when you are seeing behavior like this, but failed to share any details of their wisdom. The general issue is that when referencing a dll compiled in 2008 in a 2010 project 'is that VS 2010 requires you have Designers separate from the main assembly.' I tried contacting people there, but there seem to be no real activity on any thread in the forum at all. That leads me to my first question...
The Question(s)
1.) Hoping beyond hope, is there anybody on StackOverflow that has successfully done this for the treeviewadv project specifically? If so, I would really appreciate either a somewhat detailed description of what was done, or a short description with the final resulting code/fix. While I understand this is highly unlikely, I thought I would ask before asking more general questions on 'how to'?
2.) Barring anybody that fits the bill for number 1, is there anybody that has knowledge of this general process and at least enough knowledge of the TVA project and desire to work with me on this endeavor?
2.) Barring 1 and 2, is there anybody that has done this with any project and can either describe the general process in relative detail, and/or point to example code?
3.) Barring 1, 2 and 3, is there a particularly good resource that I can access that outlines how to update a VS2008 project in the manner described above?
Disclaimer
I understand that this process might be too involved to discuss here, so am willing to take the discussion/effort elsewhere if needed. If someone of category 1 or 2 can (answer my question/work with me on this) and you feel the discussion should be taken elsewhere please inform me as to how we can contact each other as there seems to be no formal mechanism on S.O.. I am still interested in posting (or linking) the results here for all to share if an answer can be found.
Here is a bit more info addressing the general issue of a Designer in a different assembly. There are some caveats: first I (we?) are not sure that the core problem as to do with a UI Designer. Given the project appears to be a custom TreeView, it seems likely to be the case, but the term 'Designer' could be used in a more generic fashion for this control. A second caveat is that all I have to go on is the description above and havent seen the code for the control.
That said, I am just finishing a drop in UnDo Manager component (ie it inherits from Component and sits in the form tray). Part of what it needed was a way for the dev to select controls on the form to be subject to UnDo. The layout/construction is this:
Imports Plutonix.UIDesigners
Namespace Plutonix.UnDoMgr
Public Class UndoManager
Inherits Component
Implements ISupportInitialize
Private _TgtControls As New Collection(Of Control)
<EditorAttribute(GetType(UnDoControlCollectionUIEditor), _
GetType(System.Drawing.Design.UITypeEditor))> _
<DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
Public Property UnDoTargets() As Collection(Of Control)
Get
Return _TgtControls
End Get
Set(ByVal value As Collection(Of Control))
If value IsNot Nothing Then
_TgtControls = value
Else
_TgtControls.Clear()
End If
End Set
End Property
'...
The <EditorAttribute... decoration specifies that this component uses a special designer called UnDoControlCollectionUIEditor. If the project you are converting does not have this on one or more properties, the issue may not be related to UI designers.
Later, there is the UI editor for the COntrols collection editor. This is a separate class though it is in the same file:
<System.Security.Permissions.PermissionSetAttribute( _
System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust")> _
Public Class UnDoControlCollectionUIEditor
Inherits ControlCollectionUIEditor
Public Sub New()
MyBase.bExcludeForm = True
MyBase.bExcludeSelf = True
' create a list of supported control TYPES
typeList.Add(GetType(TextBox))
'... 9 more lines adding control types to List(of System.Type)
End Sub
End Class
Nearly all the code resides in the base class ControlCollectionUIEditor which is in a different assembly (a DLL). My component though is actually using one defined locally, so as a test, I changed the editor to use to ControlCollectionUIEditor which is the base class in my designer DLL. Labels, panels, GroupBoxes etc dont have/need UnDo capability so my Designer exempts them from showing in the Designer - when I use the base class, they all show up in the designer list as expected.
ALL the standard UI Editors (String Collection Editor and the like) are in NET assemblies, so are defined in one assembly and used in another (yours/ours/the devs). A few years ago, I decided to put several different UIDesigners I had written into a UIDesigner.DLL (ie their own assembly) and they worked fine.
Beyond that, I am confused on some specifics. It sounds like you are trying to use this 2008 assembly (a DLL?) in your conversion. Is that where the designer is? If so, it is already in another assembly from your VS 2010 project, so why is there an issue? Can the whole thing be avoided by also converting whatever is in this 2008 assembly (still not clear on what is in it).
HTH
EDIT
I had a quick look at the source, and it is using at least 1 UIDesigner. TreeViewAdv.Properties.cs defines NodeControlCollectionEditor as a custom controls collection editor for the NodeControls property. The Editor is in NodeControlsCollection.cs. Coincidentally, it is doing EXACTLY what my UnDoManager does: define what control types are valid for a CollectionEditor. Your thing then calls the standard NET CollectionEditor, mine calls the CodeProject DialogForm version. There is also a StringCollectionEditor.cs file but I cant tell if that is a UI Designer or something for the user at runtime.
Since you have the code for these, you should be able to mimic something like what I did above. I would also verify that VS 2010 does indeed have the quirk mentioned. But I am also confused what is in the 2008 assembly. Is there some piece that you dont have the source for? You might also try adding the security attribute to any UI Designers in the project since the CS version does not have them and the msg quoted indicates something about 'protection level'. It seems unlikely to help, but since you are dealing with a quirk, who knows...?
Also, that is a pretty ambitious conversion project!
Cause of Problem Verified
First, I would like to point out that indeed, the issue of losing track of the namespace in the referenced dll was because of the presence of custom UI editor/designers in that dll.
The Fix
The general process of separating Custom Editors/Designers from a 'primary' class library is this:
1.) Find all custom editors/designers in the project. If you are only somewhat familiar with the project, a good way to do that is to Find (Ctrl + F) 'UITypeEditor' in the entire solution. If you are the one who designed it, then you should have no problem.
2.) Delete or comment out the entire custom editors/designers class(es). I prefer commenting out for easy documentation (just in case you need to go back).
3.) Create new project in solution. If you cannot see the solution (i.e. you can only see the project) go to tools-->options-->Projects and Solutions. There you will see a check box that says 'Always show solution'. After revealing the solution, right click and select add-->New Project... Can be named whatever, that will have little to no effect on the code.
4.) Within the new project rename Class1 to whatever is convenient. Transfer all 'using' statements at the top of the files that originally held the custom editor/designer classes. EDIT: Add using statements for any namespaces that would allow you to access the types needed from the primary project. Declare the appropriate namespace for each class. Copy and paste custom classes into correct namespaces (You can, if you want, place ALL of your custom editor/designers in this one file). Change any classes that are declared as 'internal' to 'public' (internal is only the scope of the assembly).
5.) If the new project requires any references, add those now. If your custom editor is editing custom types, you will likely need a reference to the project that defines those types. If those types are defined in your 'primary' assembly this can get a bit tricky as it could cause a circular reference issue. One way to get around this, and probably the right way, is to remove the declaration of those types from your primary assembly and create a new project/assembly just for their declaration. If they are, for some reason, inseparable from your primary assembly, set aside a successful build (dll) previously made of you primary assembly and reference that. This reduces future sustainability of code as those types may chance, but gets the job done now if that is what you want.
6.) After debugging the custom editor/designer project, build it and add that project's build (dll) as reference in the primary project/assembly.
7.) Debug internally, create a new project in solution and add BOTH dlls (Primary and Custom Editor) to the references. Verify controls/properties behave as they are supposed to in both design time AND run time.
8.) Finally, debug externally. Create new solution, reference both dlls, verify functionality. It may seem overkill to debug in both the native solution and externally, but I found many differences in behavior between the environments. Be thorough.
Important Note: I spent a LONG time figuring that both dlls needed to be added. You see, when adding just the primary dll to the test project, it would act as though BOTH were added. I though this was reasonable (& quite dandy) as the primary assembly references the other assembly. However, close and open Visual Studio and it does not work. Long story short add BOTH dlls.
TreeViewAdv Specifics
1.) There were two Custom UIEditors. The first is in NodeControlsCollection.cs called NodeControlCollectionEditor, which inherits the standard .NET CollectionEditor. The only functionality added was the explicit assigning of what kind of controls the editor is allowed to work with. It seems this was largely done as a workaround to allow ALL NodeControl types to be added to the collection (this required the passing of type NodeControl), but get around the fact that passing the NodeControl type causes an error because you cannot instantiate an abstract type. The second is StringCollectionEditor in StringCollectionEditor.cs. This also inherets the standard .NET CollectionEditor and adds a little functionality (Not sure of the purpose).
2 - 4.) Same as the general process.
5.) I currently had to use the latter method (setting aside a dll of Aga.Controls for my custom UIEditor to reference). Later I hope to separate some of the object declarations from the primary assembly to make the solution more reliable.
6 - 8.) The original bug (losing the aga namespace) did not occur when running the testing application inside the same solution (even if different project). Additionally, some fixes that worked externally did not run correctly internally and vise-versa. Thus, my advice for testing in both environments.
Final Request
While both the general and specifics of my question is answered here, Plutonix's help was vital in my coming to the solution. While I am marking this as the answer. I would like if people also upvote Plutonix's answer given the effort that he has put forth in helping me find the answer (in addition to the fact that his answer is also correct if less specific).
EDIT: The process outlined above worked when I was modifying the original TVA C# code. I was even able to reference and successfully use the resulting DLLs in a VB.net project. When I tried to apply the same process to the TVA code line that I had converted into VB.net, it resulted in the same problem that I started with. Everything works until I go to run the application and then it loses sight of the aga namespace.
EDIT SOLUTION: Go to properties (of project losing reference)--> Compile tab --> Advanced Compile Options button. Under target framework, change to ".NET Framework 4" if not so already. If that value is already selected, you are likely looking at a different cause.

Change each c# file in solution

Is there a tool or set of tools to go through a c# solution and automatically perform certain changes such as enforcing naming schemes and change for/foreach to linq if possible.
I have used Resharper to do some basic solution wide changes, but I would really like it to do more like global renaming.
Specifically, I would like a tool to rename method parameters to proper c# naming schemes. For instance, MethodA(string Field) should become MethodA(string field) and so on.
Resharper has some pretty cool features, including "Cleanup Code", which can be run on multiple files at once.
It will automatically refactor your files based on the settings you've supplied it.
They have a demo version, so you can test to see if it helps with your problem.
http://www.jetbrains.com/resharper/
Resharper`s "Clean Up Code" tool can be run from context menu of any item in Solution Explorer. There are a few built in clean up configurations. You can configure your own. For example, you can set up order of fields\properties\methods\nested types in you class and reordering their before commit by executing clean up tool. It also can wrap its into region and so on.
Also you can force Resharper to use any of refactorings when cleaning up.(Optimize imports, remove unused methods or properties or use linq instead of loops, etc)
You can start looking from there
UPD You can use stylecop plugin to make your code correspond with the style conventions you want. It is open source and compatible with R#

how to do a "Move type to another file to match its name" accross a complete solution

does anyone know of a way to split all classes in one solution into multiple files?
The point here is that I've inherited a project in which a few hundred files contain a thousand or so classes...
I'd like to be able to get to a 1 file per class approach..
Using resharper I can easily do this manually, but I'm guessing there must be a better way?
Kind regards
Frederik
You could try one of the ReSharper 5.0 nightly builds which allow you to do it across your whole solution. You can revert to ReSharper 4.5 (or whatever version you are using) afterwards.
GraemeF's answer is correct, but when you do that refactoring chances are you'll lose all source-control history for the existing classes. This might not be a problem for you (especially if the system you've inherited wasn't source-controlled!) but I've often found that line-annotated views of a class are very helpful for determining the intent behind a particular line.
ReSharper has the Ctrl-T shortcut to jump to a type name, and holding down Ctrl makes types clickable; that might be another way to solve your problem.

Categories

Resources