Is it possible to define your keywords in C#?
I mean something like
public important Form newform;
where important would be the new keyword. It would mean something like, for example, that if the type is null when compiling an error occurrs. So the example would produce an error. An example with no error would be
public important Form newform = form1;
No, the compiler doesn't allow you to add keywords out of box.
That doesn't mean you can't accomplish what you want, but it's going to be non trivial. You're going to need to perform your own custom static code analysis.
Roslyn
One way to do it is via the new .NET Compiler Services (Roslyn) Code Analyzers. You can read this MSDN article to get started: https://msdn.microsoft.com/en-us/magazine/dn879356.aspx and you'll end up with something that looks like this:
This will work from within Visual Studio, and you can generate at least Warnings, I would assume Errors as well (or you'll have to turn on "Treat Warnings as Errors").
Because you want to declaritively add the check to certain variables, you'll need to make use of Attributes:
/// <summary> Indicate a variable must be given a value
/// in the same line it's declared </summary>
public class ImportantAttribute : Attribute {}
public class Program
{
[Important]
object thisShouldError;
object thisIsFine;
}
Then when you write your Analyzer you'll need to check the variable declaration node to see if it's decorated with Important.
If you want this to work on a build server (or outside of VS), you might need to do some more work: Roslyn: workspace loads in console application but not in msbuild task
StyleCop
The easiest way is probably to use Code Analysis (ie StyleCop) to run Static Analysis Rule Sets against your code base:
You'll need to write your own Rule Set and I don't know if the Rule Sets will give you fidelity to be able to declare which variable declarations you want to force a check on, ie I don't know if you'll be able to mix & match this:
public class Program
{
[Important]
object thisShouldError;
object thisIsFine;
}
Fody
Another approach is to use an IL weaving tool like Fody that lets you manipulate the IL of your application during compilation. AFAIK you can't directly generate compilation errors, but you might be able to add invalid IL that will in turn generate a compile time error.
So based on the same code as above, after a compilation pass with Fody you'd end up with code like:
public class Program
{
[Important]
object thisShouldError YouForgotToInitializeThisImportantVariable;
object thisIsFine;
}
Custom Compiler
Microsoft did open source the C# compiler: https://github.com/dotnet/roslyn. So if you're feeling really ambitious, you can absolutely add in your own keywords in your own fork of the compiler. Of course then you'll essentially have your own language and it won't be able to compile on anything other than your custom compiler.
Short: No you can't.
Long: It is possible, but it it's probably never happening, as you would require for the C# team to add it, but that would require a lot of discussion and a lot of feasible uses for it.
Maybe you can simply use tools like ReSharper... To define new keyword only for finding uninitialized public variables sounds as bad idea.
No, you cannot create a new keyword in the way you have indicated. I suggest you take a look at this.
Create new keyword for C# automatic property
Related
Often I have the pieces of code that look like this:
private void OnChangeLanguageCommandExecuted(object obj)
{
pLngService.ChangeLanguage(newLcid);
}
In this case the ChangeLanguage(...) method returns a value, although that value (true for success, false for non-success) is not used. The problem is, I had no clue when looking at the code that this method was returning a value.
I did not write the method, nor have I control over it.
Therefore i'd like to globally enforce a policy where:
Each non-void returning method must be assigned a variable, e.g.
var unused = pLngService.ChangeLanguage(newLcid);
Or the discard operator should be used, to make it more explicit:
_ = pLngService.ChangeLanguage(newLcid);
I'm of course open to other suggestions, the main goal here is to make it more verbose that both a method is returning a value and that i'm choosing to discard it.
I was hoping there'd be a rule for visual studio or Resharper where i could enfore this policy by generating compiler warnings. I won't like to make this a compiler error, that seems to rigorous. I did some quick looking around but i did not find anything oob but i feel like im overlooking something.
I'm using projects in vs2017 (net4) and vs2019 (net8/netcore3.0) so something that would work in either of those setups would be great.
EDIT:
I found out, literally whilst writing a roslyn code analyzer, that apperently you can configure this with https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0058
The code fixes were exactly what I was looking for:
// Original code:
System.Convert.ToInt32("35");
// After code fix for IDE0058:
// csharp_style_unused_value_expression_statement_preference = discard_variable
_ = System.Convert.ToInt32("35");
// csharp_style_unused_value_expression_statement_preference = unused_local_variable
var unused = Convert.ToInt32("35");
There is the following rule:
csharp_style_unused_value_expression_statement_preference
With options:
Option values discard_variable - Prefer to assign an unused expression to a discard
unused_local_variable - Prefer to assign an unused expression to a local variable that is never used
For future readers, please refer to the code rule IDE0058:
https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0058
Also see: https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/code-style-rule-options?view=vs-2019 on how to configure editor rules.
Which should provide what you need. If thats not available, or the rule is buggy in your particular version of VS you can also take a look at this quick roslyn analyzer i made on a saturday morning:
https://github.com/sommmen/DiscardReturnValueAnalyzer/tree/master
She works but there are still some things i'm not happy with, like the actual analysis messages. But since IDE0059 should already cover this use case I'm not putting more effort into this. If you need this for some reason, feel free to create an issue and I might take a look.
Also the repo is not published or something so you'd have to clone and build it yourself.
P.s. Roslyn analyzers are pretty dope once you get the hang of them.
Multiple enumeration of the same enumerable is something that has been a performance problem for us, so we try to stomp those warnings in the code. But there is a generic extension function that we have for throwing null parameter exceptions that generates a lot of these warnings. Its signature looks like this:
public static void VerifyArgumentIsNotNull<T>(this T value, string valueName) where T : class
All it does is check for null and throw a nicely formatted and localized (for whichever human language is in play at the time) exception.
When this function is used on an IEnumerable parameter, it makes the code analysis warn about a possible multiple iteration of the IEnumerable because the analyzer has no idea what that function does.
I would like to put some tag on this function that says, "Yes, this takes the enumerable as an input, but it does not iterate it and therefore should not be counted as a possible iteration by callers." Is there any such tag? I've searched the Internet to no avail.
Yes, what you're asking is very much possible, but requires a little work. ReSharper uses Code Annotations to add hints to its analysis engine and make more sense of the code it has to work with. I recently recorded a webinar with JetBrains called ReSharper Secrets, where I go into much greater detail about what Annotations are and how to use them. You should watch it!
There's an annotation attribute, [NoEnumeration] that does exactly what you ask - specifies that the given IEnumerable argument is not enumerated, however it's not included in the default Code Annotation Attributes, however it is defined in the JetBrains.Annotations.dll assembly.
So after this introduction, here's what you need to do:
(if you haven't already,) go to ReSharper Options, then Code Inspection → Code Annotations, and press the Copy default implementation to clipboard button
Create a file in any of your (shared) projects called Annotations.cs (or any other name)
Paste the code from the clipboard, completely replacing anything that was previously in Annotations.cs
Add the following definition at the end of the file:
Code:
/// <summary>
/// Indicates that IEnumarable, passed as parameter, is not enumerated.
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class NoEnumerationAttribute : Attribute
{
}
After you done this, all that's left to do is place the [NoEnumeration] attribute on the value argument, like this:
public static void VerifyArgumentIsNotNull<T>([NoEnumeration] this T value, string valueName) where T : class
{
....
}
And that's it! The warning will disappear!
Bonus:
There are 3 additional attributes you can use to decorate this method to make it even more useful: [NotNull], [ContractAnnotation] and [InvokerParameterName]. I recently describe what they do (and a short demo) in this issue for a similar API called LiteGuard.
Annotations are fun :)
Since VerifyArgumentIsNotNull is generic, but does nothing type specific, it can take an object:
public static void VerifyArgumentIsNotNull(this object #object, string argumentName) { ... }
Resharper (9.11.) assumes that the called method does not cast #object back to an IEnumerable, and thus there is no warning.
Note the lack of the class constraint means the compiler may not warn if you accidentally pass a value type to VerifyArgumentIsNotNull, but Resharper will warn that a value type can never be null.
This approach has the additional advantage of saving the JIT from creating an instance (closed generic) method for every type that VerifyArgumentIsNotNull is called with; a micro-optimization to be sure, but a rare example where a generic may not be preferable to an old-school object.
One possible drawback to the above: I have seen similar implementations where VerifyArgumentIsNotNull returns "value". In this case a return value of type T is needed to avoid an explicit cast. (IMO this syntax is ugly. So it is not a drawback for me.)
Two other editorial comments:
1. A method name I have seen: ThrowIfNull is more concise, and "Throw" is more explicit than "Verify"
2. I no longer use methods for this, because without an annotation on VerifyArgumentIsNotNull Resharper must assume the argument could still be null. I find it much simpler to let R#, insert a 1-line if + throw when I add the NotNullAttribute.
This approach does not work for the broader case where you want to ensure that a method is called with an enumerable. In this case Igal Tabachnik's additions to Annotations are great.
Assuming you are using Visual Studio 2013/2012 (I'm only aware of this feature in 2013 though) in the code analysis window you should be able to right click the message navigate to Suppress Message > In Source File or In Suppression File
Alternatively you can achieve the same effect by clicking the action drop down of the message in the Code Analysis window.
I have fields in one class and I want to move them to another class. Creating the new fields is not that much work. Changing all their references from the class they were in until now, however - is.
‘Rename’ doesn’t accept ‘myClass.Field’ as valid. Is changing using Find-and-Replace the only option (though then I’ll have to check every occurrence because of identically-named variables)? Or is there a simple way like ‘Rename’?
There is no (built-in) refactoring that will move a variable to another type. Some third party refactoring tools (such as Resharper) do include this as additional features.
However, I would recommend letting the compiler help you instead of relying on Find and Replace. If you remove the original variables, every access of the variable will become an instant compiler error. This will give you all of the usages without false positives.
Here is what I would do:
1. Ensure everything compiles well first :)
2. Move your variable into the new class MyClass
3. Add a field MyClass myClass to the original class and instantiate it in the constructor
4. Using a text editor (as VS does not allow this) search for all instances of Field and replace them by myClass.Field
5. Back to VS, compile your code again
This should work fine and should save you some valuable time.
Regards,
I am doing work for a client who has lost the source code for one of their VB.Net WinForms applications. The assembly they have is not obfuscated at all. I am trying to recover as much of the source as I can as C# source and have tried several tools for decompiling assemblies, including Reflector, ILSpy and JustDecompile (all the latest versions), but they all produce code with a huge number of errors in them. Because of the large number of errors in the generated code, I am going to ask about the specific errors (in different questions), hopefully to get more directed answers and in this way try shed some light on why all the tools are having difficulty decompiling this assembly.
This question pertains to the fact that the code generated by all these tools always have a large number of invalid member variables (fields) such as the following:
private short $STATIC$Report_Print$20211C1280B1$nHeight;
private ArrayList $STATIC$Report_Print$20211C1280B1$oColumnLefts;
private StaticLocalInitFlag $STATIC$Report_Print$20211C1280B1$oColumnLefts$Init;
Can someone explain why the generated code has these invalid member variables and how I can resolve these?
Those are identifiers generated by the VB.NET compiler to implement the Static keyword. For example:
Class Example
Public Sub test()
Static lookhere As Integer = 42
End Sub
End Class
generates this IL:
.field private specialname int32 $STATIC$test$2001$lookhere
.field private specialname class [Microsoft.VisualBasic]Microsoft.VisualBasic.CompilerServices.StaticLocalInitFlag $STATIC$test$2001$lookhere$Init
By using reserved letters in the field name, the compiler can be sure there will never be an accidental collision with another field. There's no direct equivalent to Static in the C# language. You can leave them as private fields in the class but you have to watch out for initialization. The purpose of the $Init flag and rather a lot of IL that ensures the variable is correctly initialized. You'll need to rename them by hand.
In short, what's valid in IL isn't necessarily the same as what's valid in the source language. It's fairly common to give compiler-generated (aka synthetic in some circles) members name which are invalid in the language, as it avoids any possible clashes. These are sometimes called unspeakable names as they can't be "spoken" in the source language. For example, the C# compiler usually includes <> in such names.
As for resolving the issue - some decompilers will work out where such names have come from automatically, but you can usually simply change the name everywhere. You won't end up with the original source code, but if you look at what you do end up with, you may be able to then work out more easily what the original source did look like.
Note that the compiler may generate more than just invalid names: in C#, for example, iterators blocks generate IL which in some cases can't be expressed directly in "normal" C# itself. This may not be a problem for you, but it's worth being aware of.
Those aren't variables, they are fields (they have access modifiers).
They will be compiler generated fields which will be generated in a number of different circumstances. The names are purposely invalid to avoid conflicts with "normal" fields.
If you can provide a little more context someone clever can probably figure out what the source originally looked like for the compiler to emit those fields.
R# 4.5 (answers to 5 are welcome)
VS2008 (answers to VS2010 are welcome)
C# (FWIW)
I'm using a constructor (the question applies for methods, too), and there's Intellisense:
I don't yet have a value to specify for this first parameter, "firstName". Today, I type "firstName", then let the IDE create that variable for me (which I initialize to some value).
I understand that the IDE will create the variable for me. I want it to create the variable name for me.
I don't want to have to type "firstName". I like the variable name the parameter author chose, and I want to use that variable name in my (calling) code.
Is there a way to have these acceptable variable names re-generated for me (the calling code) automatically as I move, parameter by parameter, through this line of (calling) code?
You may get close to what you are looking for with VS2010.
Type p.Foo(
This will open the description of the currently selected constructor, out of the list of all constructors. If you type a letter, or hit ctrl + space, intellisense auto completion will open.
A difference here between VS2008 and VS2010 is named parameters. In VS2010, your completion list will have entries for the named parameters firstName: and lastName:.
Type the first letter of the parameter name (what you are referring to as "the variable name the parameter author chose")
Intellisense should jump straight to that entry, and allow you to do completion the same way it usually does.
Type a space, enter, or comma
Intellisense it will insert the identifier used for the named parameter. It won't insert the colon (unless you type it), so you don't have to use the named parameter feature to accomplish your goal here. You can just take advantage of the fact that the text you are looking for is in your completion list.
How you get Visual Studio to actually generate the local variables (which, according to your question, it seems like you have already solved) baffles me, and would be up to you to take care of :) If you've got that second problem licked, I'd like to know how, too.
You can make a code snippet that creates the variable and inserts it as parameters.
MSDN Reference on snippets
I don't understand your scenario entirely but I'm assuming you want to inject a variable name from calling assembly into the called code. if so, you may want to look into System.CodeDom that lets you create class and its memebers during runtime beside plethora of other functionality it offers.
I am pretty sure you can do it with Resharper or CodeRush/Refactor.
It sounds like to me that what your trying to do is get out of typing at all! To have the IDE put the code in you intend so you don't have to. A quite lofty goal - with the exception that you'd put us all out of work ;-(
All fun aside, what you're probably reaching for is a code gen tool such as the T4 Toolbox ( one of my new favorite toys). If you're looking for a tool that will auto-generate your code snippets as you type, that's a tall order. The nearest thing available would be Resharper.
Here is an example of a class constructor I generated from my customization of T4 Toolbox templates:
public partial class EvaluationController : SmartController
{
private readonly IEvaluationService _evaluationSvc;
private readonly IEvaluationMapper _evaluationMapper;
private readonly IEvaluationCriterionMapper _evaluationCriterionMapper;
private readonly IParticipantEvaluationMapper _participantEvaluationMapper;
public EvaluationController( IEvaluationRepository repository, IEvaluationService evaluationSvc, IEvaluationMapper evaluationMapper, IEvaluationCriterionMapper evaluationCriterion, IParticipantEvaluationMapper participantEvaluation)
{// : base(repository, evaluationMapper)
_evaluationSvc = evaluationSvc;
_evaluationMapper = evaluationMapper;
_evaluationCriterionMapper = evaluationCriterion;
_participantEvaluationMapper = participantEvaluation;
}
If that is what you're after, the place to start would be: http://t4toolbox.codeplex.com/
I've got an example project where I use customizations of the templates to spin up my business classes, various methods & repository layer.http://t4tarantino.codeplex.com/
There's an example of the level of complexity of output you can generate at
http://geekswithblogs.net/JamesFleming/archive/2010/08/18/code-generation-with-t4-toolbox.aspx
HTH