【问题标题】:How to detect which .NET language is calling my code如何检测哪种 .NET 语言正在调用我的代码
【发布时间】:2015-10-16 01:36:56
【问题描述】:

我正在构建一个库,该库生成一个用户代理字符串,该字符串报告一些漂亮的数据,如操作系统版本和currently installed .NET Framework versions。我很好奇:

是否可以以编程方式检测哪种语言正在调用我的库?还是源语言在编译成 CIL 后完全不透明?

【问题讨论】:

  • 由于应用程序可能由多种语言的片段组装而成,了解直接调用者的语言有什么好处?
  • @HABO 好奇心,主要是。我同意好处是不确定的,因为直接调用者可能甚至不能代表整个应用程序。

标签: .net reflection cil


【解决方案1】:

编辑:我把它变成了small library,它封装了一些启发式方法并使其易于调用。

我想出了一个似乎可以很好地满足我自己需求的启发式方法。

@Don 的回答和这些问题给了我一些提示:

注意事项

  • 仅区分 VB.NET 和 C#,不区分任何其他 CLR 语言。如果没有足够的 VB 证据,则假定为 C#。
  • 这是一个有根据的猜测,因此误报的可能性 > 0。
  • 一些提示基于编译器实现细节,可能会发生变化。
  • 这似乎也适用于 Mono,但 YMMV。
  • 这是一种昂贵的反射,因此在现实生活中,您需要将其包装在 Lazy<> 或其他某种机制中,以确保它只被调用一次。
  • 正如@HABO 提到的,这可能是也可能不是非常有用的信息。我主要是想看看能不能做到。

var lang = DetectAssemblyLanguage(Assembly.GetCallingAssembly());

public static string DetectAssemblyLanguage(Assembly assembly)
{
    var referencedAssemblies = assembly
        .GetReferencedAssemblies()
        .Select(x => x.Name);

    var types = assembly
        .GetTypes();

    // Biggest hint: almost all VB.NET projects have a
    // hidden reference to the Microsoft.VisualBasic assembly
    bool referenceToMSVB = referencedAssemblies.Contains("Microsoft.VisualBasic");

    // VB.NET projects also typically reference the special
    // (YourProject).My.My* types that VB generates
    bool areMyTypesPresent = types.Select(x => x.FullName).Where(x => x.Contains(".My.My")).Any();

    // If a VB.NET project uses any anonymous types,
    // the compiler names them like VB$AnonymousType_0`1
    bool generatedVbNames = types.Select(x => x.Name).Where(x => x.StartsWith("VB$")).Any();

    // If a C# project uses dynamic, it'll have a reference to Microsoft.CSharp
    bool referenceToMSCS = referencedAssemblies.Contains("Microsoft.CSharp");

    // If a C# project uses any anonymous types,
    // the compiler names them like <>f__AnonymousType0`1
    bool generatedCsNames = types.Select(x => x.Name).Where(x => x.StartsWith("<>")).Any();

    var evidenceForVb = new bool[] 
    {
        referenceToMSVB,
        myTypesPresent,
        vbGeneratedNames
    };

    var evidenceForCsharp = new bool[] {
        true, // freebie. ensures ties go to C#
        referenceToMSCS,
        csGeneratedNames
    };

    var scoreForVb = evidenceForVb.Count(x => x)
                     - evidenceForCsharp.Count(x => x);

    // In the case of a tie, C# is assumed
    return scoreForVb > 0
        ? "vb"
        : "cs";
}

【讨论】:

  • 这是一种有趣的方法,但是 C# 程序集可以引用 Microsoft.VisualBasic(它包含一些有用的类型,例如 TextFieldParser),而 VB 程序集理论上可以引用 Microsoft.CSharp(不太可能)国际海事组织)。
  • @ThomasLevesque 我同意,这在很多情况下会产生误导性的结果。它在 .NET Core 代码上也不能正常工作(或根本不能工作)。我主要把它留在这里作为一个有趣的练习。 :)
【解决方案2】:

很遗憾,这是不可能的,正如您通过提及 CIL 所确定的那样。

我能想到两种可能的解决方案:

  1. 但是,如果相应 .NET dll(调用代码的程序集)的 PDB 文件可用,那么您可以检查该文件以确定使用的语言。不过,这是一个很大的“如果”,我会远离这样的解决方案。
  2. 检查调用程序集引用的程序集。有时(很少)可能会引用特定于语言的程序集。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 2011-05-14
    • 1970-01-01
    • 1970-01-01
    • 2015-01-29
    • 1970-01-01
    相关资源
    最近更新 更多