J
Are there languages that can't live without him?The tongues, in fact, before the lamp, this attribute. Languages are required by the API, which they rewrite, the CLSCompliant attribute they can use to remove warning during the compilation while attempting to use unsupported API. Maybe not. Reality is closer to the second option. In order to illustrate this, we'll create a pilot set to interact the low-level C# and high-level JScript. NET:using System;
using System.Collections.Generic;
using Microsoft.JScript;
using System.CodeDom.Compiler;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static object JsExecute(
string script,
string[] refs,
string func,
params object[] args)
{
var jsc = new JScriptCodeProvider();
var parameters = new CompilerParameters( refs, "test.dll", true);
parameters.GenerateExecutable = false;
CompilerResults results = jsc.CompileAssemblyFromFile(parameters, new string[] { script });
if (results.Errors.Count > 0)
{
Console.WriteLine("Errors: ");
foreach (var err in results.Errors)
{
Console.WriteLine(err.ToString());
}
return null;
}
var ass = results.CompiledAssembly;
var c = ass.GetType("C");
var f = c.GetMethod(func);
return f.Invoke(null, args);
}
}
}
To make it work, you need to add a reference to Microsoft. JScript (and the project should be NET Framework - in NET Core no suitable type for integration with JS). In fact, the code takes the violin from the file, compiles and launches the reflection. I notice that results.Errors In addition to the mistakes, it also includes warnings, so we'll see what the compiler does. Now with his help, we can run the interesting API through JS and see how he'll lead himself.Pilot 1 - UInt32Let's just start by feeding the JS "non-compliant" UInt32:JS:class C {
static function calc_sum(x, y) {
return x + y;
}
}
C#:static void Main(string[] args)
{
object res = JsExecute(
"test.js",
new[] { "mscorlib.dll", "System.Core.dll" },
"calc_sum",
new object[] { (uint)1, (uint)2 });
Console.WriteLine(res);
Console.Read();
}
/* Вывод:
3
*/
As you can see, everything worked out without mistakes. In fact, it doesn't prove anything, because JScript.NET, unlike Brauser equivalent, supports uint natically ( https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2010/ddacxdt5%28v%3dvs.100%29 ) But at least our experimental code is working.Experiment 2 - Microsoft.Extensions. ConfigurationWe'll see the Microsoft mentioned.Extensions. Configuration. Fortunately, it is compatible with the new versions of NET Framework. In order to verify this code on JS, which creates ConfigurationBuilder, defines the value in the Properties dictionary and tries to count it back:import Microsoft.Extensions.Configuration;
class C {
static function test() {
var builder = new ConfigurationBuilder();
builder.Properties['key'] = 'Value';
return builder.Properties['key'];
}
}
C#:static void Main(string[] args)
{
object res = JsExecute(
"test.js",
new[] { "mscorlib.dll", "System.Core.dll", "Microsoft.Extensions.Configuration.dll" },
"test",
new object[] { });
Console.WriteLine(res);
Console.Read();
}
/* Вывод:
Value
*/
Again, everything works fine. Well, there's nothing surprising, too, to put all types on the JS system.Pilot 3 - IndicatorsNow we take what JS really doesn't support - indexes. By the way, we can't even send a direct index, but there's an API like https://docs.microsoft.com/en-us/dotnet/api/system.reflection.pointer?view=netframework-4.5 .Box/Unbox, IntPtr, which allow the indexes to be rotated. And they, as you can guess, CLSCompliant(false). We'll write the code that passes the index in JS, and in the JS code, we'll try to work with it with the tools available to it:JS:import System;
import System.Reflection;
import System.Runtime.InteropServices;
class C {
static function write_value(p) {
var ptr = new IntPtr(Pointer.Unbox(p));
Marshal.WriteInt32(ptr, 1);
}
}
C#unsafe static void Main(string[] args)
{
int x = 0;
Console.WriteLine("x before: "+x.ToString());
object res = JsExecute(
"test.js",
new[] { "mscorlib.dll", "System.Core.dll", "System.Runtime.dll" },
"write_value",
new object[] { Pointer.Box(&x, typeof(int*))});
Console.WriteLine("x after: " + x.ToString());
Console.Read();
}
/* Вывод:
x before: 0
x after: 1
/
Not only does there appear to be no warning of the use of 2 CLSCompliant(false) methods, but the code has successfully established the variable value of the indicator. The reason is that everything works under the hood, and JS never sees the need to create a direct variable-indicator. This does not mean that any API on indicators can be used in this way. If API accepts not void and allows byte*, it is no longer clear how to transform it.In short, the importance of CLSCompliantAttribute in the modern world is not so great. It needs more to shut down C# and individual FxCop analysers who fight in their absence than for the real integration of languages. Some decide to ignore the warning and not to place the attribute to save the amount of the binary. But if you just remove the attribute, it breaks the code that depends on it, which leads to a situation that doesn't even need to create, but not remove.