RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1129226
Accepted
return
return
Asked:2020-05-21 20:14:38 +0000 UTC2020-05-21 20:14:38 +0000 UTC 2020-05-21 20:14:38 +0000 UTC

.NET 规范

  • 772

我很久以前就遇到过这样的类型CLSCompliantAttribute。思路很简单:限制高级语言的接口,让相对低级的语言与之交互。但是当我从 .NET Framework 切换到 .NET Core 时,结果发现 Microsoft 的扩展(按类型Microsoft.Extensions.Configuration)不符合 CLS。

那么一个合乎逻辑的问题就出现了:既然CLSCompliantAttribute连它的创造者都不使用它,为什么在 2020 年还需要它呢?

有没有没有它就活不下去的语言?

.net
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    MSDN.WhiteKnight
    2020-05-26T14:22:11Z2020-05-26T14:22:11Z

    有没有没有它就活不下去的语言?

    语言本质上并不关心这个属性。语言需要它们消化的 API,并且它们可以在尝试使用不受支持的 API 时使用 CLSCompliant 属性发出编译时警告。或者他们可能不会使用它。现实更接近第二种选择。为了说明这一点,让我们为“低级”C# 和高级 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);
            }
        }
    }
    

    为此,您需要添加对 Microsoft.JScript 的引用(并且项目必须是 .NET Framework - .NET Core 没有与 JS 集成所需的类型)。实际上,代码从文件中获取脚本,通过反射编译和运行。我提请您注意,results.Errors除了错误之外,它还包括警告,因此我们将看到编译器 (jsc) 生成的所有内容。现在在它的帮助下,我们可以通过 JS 运行有趣的 API 并查看它的行为方式。

    实验 1 - UInt32

    让我们从简单的开始 - 让我们尝试将“不合规”的 UInt32 提供给 JS:

    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
    */
    

    如您所见,一切正常,没有错误。实际上,这并不能真正证明什么,因为 JScript.NET 与浏览器等价物不同,它本机支持 uint ( https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio- 2010/ ddacxdt5%28v%3dvs.100%29)。但至少我们的实验代码有效。

    实验 2 - Microsoft.Extensions.Configuration

    考虑提到的 Microsoft.Extensions.Configuration。幸运的是,它与新版本的 .NET Framework 兼容。为了检查,让我们编写以下 JS 代码来创建 ConfigurationBuilder,在 Properties 字典中设置值并尝试将其读回:

    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
    */
    

    同样,一切都很好。好吧,这也没什么好奇怪的——所有类型都属于 JS 类型系统。

    实验 3 - 指针

    现在让我们来看看 JS 并不真正支持的东西——指针。当然,我们甚至不能直接传递指针,但是有像Pointer .Box / Unbox、IntPtr 这样的 API 允许您包装指针以进行反射。正如您可能猜到的那样,它们是 CLSCompliant(false)。让我们编写一个将指针传递给 JS 的代码,在 JS 代码中,我们将尝试使用其中可用的工具来处理它:

    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
    */
    

    如您所见,使用 2 种方法和 CLSCompliant(false) 不仅没有警告,而且代码成功地能够通过指针设置变量的值。线索是在幕后一切都在反射上起作用,而 JS 从来没有遇到过直接创建指针变量的需要。这并不意味着指针上的任何 API 都可以以这种方式使用。如果 API 不接受 void*,但假设是 byte*,则不再清楚如何转换它。


    简而言之,CLSCompliantAttribute 在当今.NET 世界中的价值并没有那么大。与真正的语言集成相比,更需要关闭 C# 编译器本身并分离 FxCop 分析器,这些分析器发誓没有它。有些人选择忽略警告并且不设置属性以保存二进制大小。但是如果只是删除该属性,那么依赖它的代码就会崩溃,从而导致“连创作者都不需要它,但不要删除它”的情况。

    • 3

相关问题

  • 如何在 Windows 资源管理器中查找和打开路径

  • 在 EF Core 中创建迁移

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5