Add compile warnings to C# method - c#

When calling the Console.SetWindowSize, I get a nice warning telling about OS support:
Console.SetWindowSize(width, height); // Warning:
This call site is reachable on all platforms. 'Console.SetWindowSize(int, int)' is only supported on: 'windows'. csharp(CA1416)
If I wrap this in an OS check, the warning goes away:
if (OperatingSystem.IsWindows())
{
Console.SetWindowSize(width, height); // No warnings
}
Question
Is it possible to decorate a custom method so that it behaves in a similar manner, giving a warning when not wrapped in a check for OS?
I've had a look at the source (I think this is the source, anyway), and I cant see anything on the Console.SetWindowSize method that would cause this warning, so I'm not sure how it works, and thus not sure how I could leverage it in my own methods (or whether it's even possible).
Pseudo Example
A naive pseudo example of what I'd like to try and achieve.
[SupportedOperatingSystem(OS.Windows)]
public void MyWindowsOnlyMethod()
{
}
if (OperatingSystem.IsWindows())
{
MyWindowsOnlyMethod(); // No warning
}
else
{
MyWindowsOnlyMethod(); // Warning
}
Environment
Since I'm not totally sure what generates these warning, it's worth mentioning my setup:
C# 11
.Net 7
VSCode (C# extension)

Turns out the answer is almost exactly what I was hoping to do:
Use the SupportedOSPlatform attribute. E.g.
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
public void MyWindowsOnlyMethod()
{
}
if (OperatingSystem.IsWindows())
{
MyWindowsOnlyMethod(); // No warning
}
else
{
MyWindowsOnlyMethod(); // Warning
}
`

Related

Do pre-processor directives protect server code from the client?

I'm developing a client-server library. Some of the classes can be used by either the client or the server but are executed differently and yield slightly different results for each. As well, the server code may contain additional methods that will not be called from the client build.
A class may look like this:
public class StuffDoer {
public void DoStuff(object msg)
{
ServerDoStuff(msg);
ClientDoStuff(msg);
}
[Conditional("SERVER")]
private void ServerDoStuff(object msg)
{
// Do secret server stuff...
}
[Conditional("CLIENT")]
private void ClientDoStuff(object msg)
{
// Do client sutff...
}
[Conditional("SERVER")]
public void DoCoolStuff(object msg)
{
// server does cool stuff...
}
}
I've read that the Conditional attribute still compiles the code and would therefore be in the build, unlike pre-processor directives which would completely remove the code and not even compile it.
I'm concerned that a dishonest client may hack the product by unobfuscating the source code and figure out how the server works.
Are my fears unfounded or would I need to place pre-processor directives in order to hide the source code?
According to the documentation:
Applying ConditionalAttribute to a method indicates to compilers that
a call to the method should not be compiled into Microsoft
intermediate language (MSIL) unless the conditional compilation symbol
that is associated with ConditionalAttribute is defined.
When you compile with CLIENT defined, the code to call a method marked with SERVER will not be present in the final assembly. But the code for the method will be present. You cannot achieve what you need in this way.
When "SERVER" is not defined, The method be marked as "SERVER" will always compile to the final assembly but all of callings to the method will be removed.
This is code
This is decompiled result

LINQPad: Assert() prints "Fail:" and continues instead of breaking

In LINQPad, Debug.Assert() and Trace.Assert() from the System.Diagnostics namespace don't work as expected.
Instead of breaking - i.e. popping up a message box or whatever else happens to be configured for <trace> - they simply print "Fail:" or "Fehler:" to the output window and let the program continue on its merry way. In other words, instead of a noisy, unignorable explosion there are only near invisible micro-farts that intersperse "Fail:" into the textual output.
Is there any way of getting Assert() to revert to the default behaviour under LINQPad?
Alternatively, is there a simple way of mocking a Trace.Assert() so that failure results in a noisy explosion (i.e. exception, message box, whatever) and the source of the failure is pinpointed in the form of a line number or similar?
My unit tests are based on Trace.Assert(), which makes them totally useless if the function cannot break the program at the point of failure.
In Visual Studio everything works normally but not in LINQPad. I haven't fiddled with any system-wide settings but I did install Mono at some point in time. I went through all settings in LINQPad with a fine comb but to no avail. The LINQPad version is 4.57.02 (non-free), running on Windows 7 Pro (German) and Windows 8.1 Pro (English).
I googled high and wide but the only thing I could find is the topic Trace.Assert not breaking, neither showing the message box here on Stack Overflow. Its title certainly looks promising but the answers therein don't.
P.S.: I tried mocking by adding
class Trace
{
public static void Assert (bool condition)
{
if (!condition)
throw new Exception("FAIL!");
}
}
to the LINQ script and setting a breakpoint on the throw statement. Clicking on the relevant call stack entry in LINQPad's debugger takes me to the relevant source line, so this sort of works. However, I couldn't find an equivalent to FoxPro's SET DEBUG ON for invoking the debugger directly from the source code instead of having to set a breakpoint on the throw...
To answer the second half of your question, i.e., how do you get the LINQPad debugger to break when an exception is thrown, the answer is to click either of the 'Bug' icons on the toolbar.
Click Break when exception is unhandled (red bug) to make your query break whenever an unhandled exception is thrown.
Click Break when exception is thrown (blue bug) to make your query break whenever an exception is thrown, whether or not it is handled.
You can get LINQPad to make either setting the default by right-clicking and choosing Set as default. (Doing so forces the debugger to always attach to your queries, which incurs a small performance cost.)
As to why Debug.Assert(false) doesn't display a dialog, this is because this behavior hasn't been implemented in LINQPad. You could implement this easily as an extension, by adding the following code to My Extensions:
public class NoisyTracer : TextWriterTraceListener
{
public static void Install()
{
Trace.Listeners.Clear();
Trace.Listeners.Add (new NoisyTracer (Console.Out));
}
public NoisyTracer (TextWriter writer) : base (writer) { }
public override void Fail (string message, string detailMessage)
{
base.Fail (message, detailMessage);
throw new Exception ("Trace failure: " + message);
}
}
Then, to enable, write your query as follows:
NoisyTracer.Install();
Debug.Assert (false);

Within my yield return function, if (false) is sending the control inside if's body [duplicate]

Given this gem of code:
class Program
{
private static bool IsAdmin = true;
static void Main(string[] args)
{
if (!IsAdmin)
{
throw new Exception();
}
try
{
var x = 2342342;
var y = 123132;
}
catch (Exception)
{
throw;
}
}
}
Given the this.IsAdmin yields true - I would expect the debugger to not enter that if statement. In reality it does - and it steps over the throw but does not actually throw!
Now this only happens when you have an exception inside an if statement followed by a try/catch block, on Visual Studio 2013, targeting .NET Framework 4, 64 bit, "Prefer 32 bit" unchecked.
I have confirmed this oddity with colleagues on different machines. Step though the following code and the debugger will seem to step into the if branch, but no exception is thrown:
I am in debug mode, I have tried compiling and cleaning the project multiple times.
Can anyone explain why this is happening?
This is a known problem caused by the x64 jitter, it occasionally generates bad debug line number info. It can fumble when a statement causes extra NOPs instructions to be generated, intended to align code. The first NOP becomes the line number, instead of the instruction after the NOPs. This bytes in a few places, like a throw statement after a simple if() test and usage of the ?? operator with simple scalar operands. These alignment NOPs are also the reason why it is so dangerous to abort threads, described in this post.
Simplest workaround is Project + Properties, Build tab, tick the "Prefer 32-bit" option if available, set the Platform target to x86 otherwise. Note how nothing actually goes wrong, while the debugger suggests that the throw statement is going to be executed your program doesn't actually throw an exception.
It is being worked on, the x64 jitter was drastically rewritten, a project named RyuJIT. It will ship in VS2015, currently in Preview.
Check out this link. It's a known bug in some versions of visual studio and the .NET framework version. It's completely harmless and something you will just have to live with.

Compilter Directives - Suggestion - Run code in Debug mode only

I need to Log messages only when application is running in debug mode. I have found 2 ways:
First: Need to write 3 lines everywhere when logging is needed. But, Logger statement is disabled at compile time only which is exactly I need. Logger.Log will not be executed at all.
#if DEV_ENV
Logger.Log("Application started !"); // This line is grayed. Perfect !
#endif
public static void Log(string message)
{
Debug.WriteLine(message);
}
Second: Very neat. Only one line of code wherever logging is required. Not sure, whether Logger.Log statement is executed or not. If function call is removed at compile time only (same as first approach. But, now sure as line of code is not greyed out), I want to go with this.
Logger.Log("Application started !"); // This line is not grayed out. But, function is not called. So, confused whether its removed at compile time.
[Conditional("DEV_ENV")]
public static void Log(string message)
{
Debug.WriteLine(message);
}
I am concerned about the performance differences.
From the MSDN page for the ConditionalAttribute:
Applying ConditionalAttribute to a
method indicates to compilers that a
call to the method should not be
compiled into Microsoft intermediate
language (MSIL) unless the conditional
compilation symbol that is associated
with ConditionalAttribute is defined.
So, as it says, the method call is removed at compile time, same as the #if.
Depending on your compile settings, you could use:
if (System.Diagnostics.Debugger.IsAttached)
Logger.Log("Application started !");
or,
#if DEBUG
Logger.Log("Application started !");
#endif
As George points out, the method call will not be compiled if the Conditional attribute is applied. This also means (as with removing the code directly using #If DEV_ENV) that any side effects included in the method call will also not occur - as always, the warning about having side effects in logging code are well founded:
public static void Main(String[] args)
{
int i = 92;
Log(string.Format("{0} became {1}", i++, i));
Console.WriteLine(i);
Console.ReadLine();
}
[Conditional("SKIP")]
private static void Log(string msg)
{
Console.WriteLine(msg);
}
If SKIP is not defined, this code prints out 92. If SKIP is defined, it prints 92 became 93 and 93.

Uniformly handling error codes in an unmanaged API

I'm writing a wrapper around a fairly large unmanaged API. Almost every imported method returns a common error code when it fails. For now, I'm doing this:
ErrorCode result = Api.Method();
if (result != ErrorCode.SUCCESS) {
throw Helper.ErrorToException(result);
}
This works fine. The problem is, I have so many unmanaged method calls that this gets extremely frustrating and repetitive. So, I tried switching to this:
public static void ApiCall(Func<ErrorCode> apiMethod) {
ErrorCode result = apiMethod();
if (result != ErrorCode.SUCCESS) {
throw Helper.ErrorToException(result);
}
}
Which allows me to cut down all of those calls to one line:
Helper.ApiCall(() => Api.Method());
There are two immediate problems with this, however. First, if my unmanaged method makes use of out parameters, I have to initialize the local variables first because the method call is actually in a delegate. I would like to be able to simply declare a out destination without initializing it.
Second, if an exception is thrown, I really have no idea where it came from. The debugger jumps into the ApiCall method and the stack trace only shows the method that contains the call to ApiCall rather than the delegate itself. Since I could have many API calls in a single method, this makes debugging difficult.
I then thought about using PostSharp to wrap all of the unmanaged calls with the error code check, but I'm not sure how that would be done with extern methods. If it ends up simply creating a wrapper method for each of them, then I would have the same exception problem as with the ApiCall method, right? Plus, how would the debugger know how to show me the site of the thrown exception in my code if it only exists in the compiled assembly?
Next, I tried implementing a custom marshaler that would intercept the return value of the API calls and check the error code there. Unfortunately, you can't apply a custom marshaler to return values. But I think that would have been a really clean solution it if had worked.
[return:
MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(ApiMethod))]
public static extern ErrorCode Method();
Now I'm completely out of ideas. What are some other ways that I could handle this?
Follow ErrorHandler class from the Visual Studio 2010 SDK. It existed in earlier versions, but the new one has CallWithCOMConvention(Action), which may prove valuable depending on how your API interacts with other managed code.
Of the available methods, I recommend implementing the following:
Succeeded(int)
(Failed() is just !Succeeded(), so you can skip it)
ThrowOnFailure(int)
(Throws a proper exception for your return code)
CallWith_MyErrorCode_Convention(Action) and CallWith_MyErrorCode_Convention(Func<int>)
(like CallWithCOMConvention, but for your error codes)
IsCriticalException(Exception)
(used by CallWith_MyErrorCode_Convention)
What happens if you don't check ErrorCode.SUCCESS? Will your code quickly fail and throw an exception? Can you tell which unmanaged API failed if your managed code throws? If so, consider not checking for errors and just letting the runtime throw when your unmanaged API fails.
If this is not the case, I suggest biting the bullet and following your first idea. I know you called it "frustrating and repetitive", but after coming from a project with a "clever" macro solution to a similar problem, checking return values in method calls and wrapping exceptions is the doorway to insanity: exception messages and stack traces become misleading, you can't trace the code, performance suffers, your code become optimized for errors and goes off the rails upon success.
If a particular return value is an error, thow a unique exception then. If it might not be an error, let it go and throw if becomes an error. You said you wanted to reduce the check to one line?
if (Api.Method() != ErrorCode.SUCCESS) throw new MyWrapperException("Api.Method broke because ...");
Your proposal also throws the same exception if any method returns the same "common error code". This is another debugging nightmare; for APIs which return the same error codes from multiple calls, do this:
switch (int returnValue = Api.Method1())
{
case ErrorCode.SUCCESS: break;
case ErrorCode.TIMEOUT: throw new MyWrapperException("Api.Method1 timed out in situation 1.");
case ErrorCode.MOONPHASE: throw new MyWrapperException("Api.Method1 broke because of the moon's phase.");
default: throw new MyWrapperException(string.Format("Api.Method1 returned {0}.", returnValue));
}
switch (int returnValue = Api.Method2())
{
case ErrorCode.SUCCESS: break;
case ErrorCode.TIMEOUT: throw new MyWrapperException("Api.Method2 timed out in situation 2, which is different from situation 1.");
case ErrorCode.MONDAY: throw new MyWrapperException("Api.Method2 broke because of Mondays.");
default: throw new MyWrapperException(string.Format("Api.Method2 returned {0}.", returnValue));
}
Verbose? Yup. Frustrating? No, what's frustrating is trying to debug an app that throws the same exception from every line whatever the error.
I think, the easy way is to add aditional layer.
class Api
{
....
private static ErrorCode Method();//changing Method to private
public static void NewMethod()//NewMetod is void, because error is converted to exceptions
{
ErrorCode result = Method();
if (result != ErrorCode.SUCCESS) {
throw Helper.ErrorToException(result);
}
}
....
}
Create a private property to hold the ErrorCode value, and throw the exception from the setter.
class Api
{
private static ErrorCode _result;
private static ErrorCode Result
{
get { return _result; }
set
{
_result = value;
if (_result != ErrorCode.SUCCESS)
{
throw Helper.ErrorToException(_result);
}
}
}
public static void NewMethod()
{
Result = Api.Method();
Result = Api.Method2();
}
}
Write a T4 template to do the generation for you.
Your existing code is actually really, really close. If you use an expression tree to hold the lambda, instead of a Func delegate, then your Helper.ApiCall can pull out the identity of the function that was called and add that to the exception it throws. For more information on expression trees and some very good examples, Google Marc Gravell.

Categories