我正在使用.NET Core 2.2开发一个Windows项目。明年我将在Linux上构建和支持它。我正在寻找一种方法,在代码中使用PlatformNotSupportedException时标记错误并中断构建。
我看过.NET API分析器,但它仍处于预发布阶段,自去年以来没有更新。
我看过.NET API分析器,但它仍处于预发布阶段,自去年以来没有更新。
Mono.Cecil
来检查程序集中是否有异常被抛出。public static class ExceptionHelper<TException> where TException : Exception
{
private static readonly string typeName = typeof(TException).FullName;
public static void ThrowIfDetected(Assembly assembly)
{
var definition = AssemblyDefinition.ReadAssembly(assembly.Location);
var exceptions = CreateExceptions(definition);
if (exceptions.Any())
throw new AggregateException(exceptions);
}
public static void ThrowIfDetected(params Assembly[] assemblies) =>
ThrowIfDetected(assemblies as IEnumerable<Assembly>);
public static void ThrowIfDetected(IEnumerable<Assembly> assemblies)
{
var exceptions = CreateExceptions(assemblies);
if (exceptions.Any())
throw new AggregateException(exceptions);
}
private static IEnumerable<Exception> CreateExceptions(IEnumerable<Assembly> assemblies) =>
assemblies.Select(assembly => AssemblyDefinition.ReadAssembly(assembly.Location))
.SelectMany(definition => CreateExceptions(definition));
private static IEnumerable<Exception> CreateExceptions(AssemblyDefinition definition)
{
var methods =
definition.Modules
.SelectMany(m => m.GetTypes())
.SelectMany(t => t.Methods)
.Where(m => m.HasBody);
foreach (var method in methods)
{
var instructions = method.Body.Instructions
.Where(i => i.OpCode.Code == Code.Newobj && // new object is created
((MethodReference)i.Operand).DeclaringType.FullName == typeName && // the object is 'TException'
i.Next.OpCode.Code == Code.Throw); // and it's immediately thrown
foreach (var i in instructions)
{
var message = $"{definition.FullName} {method.FullName} offset {i.Offset} throws {typeName}";
yield return new Exception(message);
}
}
}
}
public static class AssemblyExtensions
{
public static Assembly[] ReflectionOnlyLoadReferencedAssemblies(this Assembly assembly) =>
assembly.GetReferencedAssemblies()
.Select(a => Assembly.ReflectionOnlyLoad(a.FullName))
.ToArray();
}
使用方法:
创建一个新的控制台应用程序,并添加对包含上述代码的程序集的引用。尝试:
try
{
ExceptionHelper<PlatformNotSupportedException>.ThrowIfDetected(Assembly.GetEntryAssembly().ReflectionOnlyLoadReferencedAssemblies());
}
catch(AggregateException e)
{
foreach (var inner in e.InnerExceptions)
Console.WriteLine($"{inner.Message}\n");
}
它给出:
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Void System.Environment::SetEnvironmentVariable(System.String,System.String) offset 82 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.String System.Environment::InternalGetFolderPath(System.Environment/SpecialFolder,System.Environment/SpecialFolderOption,System.Boolean) offset 75 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Void System.Security.Principal.SecurityIdentifier::.ctor(System.Security.Principal.WellKnownSidType,System.Security.Principal.SecurityIdentifier) offset 49 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Int32 System.Security.Principal.Win32::CreateWellKnownSid(System.Security.Principal.WellKnownSidType,System.Security.Principal.SecurityIdentifier,System.Byte[]&) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Boolean System.Security.Principal.Win32::IsEqualDomainSid(System.Security.Principal.SecurityIdentifier,System.Security.Principal.SecurityIdentifier) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Int32 System.Security.Principal.Win32::GetWindowsAccountDomainSid(System.Security.Principal.SecurityIdentifier,System.Security.Principal.SecurityIdentifier&) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Boolean System.Security.Principal.Win32::IsWellKnownSid(System.Security.Principal.SecurityIdentifier,System.Security.Principal.WellKnownSidType) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.IntPtr System.StubHelpers.HStringMarshaler::ConvertToNative(System.String) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.IntPtr System.StubHelpers.HStringMarshaler::ConvertToNativeReference(System.String,System.Runtime.InteropServices.WindowsRuntime.HSTRING_HEADER*) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.String System.StubHelpers.HStringMarshaler::ConvertToManaged(System.IntPtr) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Void System.StubHelpers.SystemTypeMarshaler::ConvertToNative(System.Type,System.StubHelpers.TypeNameNative*) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Void System.StubHelpers.SystemTypeMarshaler::ConvertToManaged(System.StubHelpers.TypeNameNative*,System.Type&) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Int32 System.StubHelpers.HResultExceptionMarshaler::ConvertToNative(System.Exception) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Exception System.StubHelpers.HResultExceptionMarshaler::ConvertToManaged(System.Int32) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.IntPtr System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal::StringToHString(System.String) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.String System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal::PtrToStringHString(System.IntPtr) offset 17 throws System.PlatformNotSupportedException
mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Void System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal::FreeHString(System.IntPtr) offset 17 throws System.PlatformNotSupportedException
现在你可以在单元测试(例如使用NUnit
)中使用它,自动检查你的引用程序集是否会抛出PlatformNotSupportedException
[TestFixture]
public class Tests
{
[Test]
public void ReferencedAssembliesDoNOtThrowPlatformNotSupportedException()
{
Assert.DoesNotThrow(() => ExceptionHelper<PlatformNotSupportedException>.ThrowIfDetected(yourAssembly.ReflectionOnlyLoadReferencedAssemblies()));
}
}
并且,如果测试失败,请像这里所描述的那样中断构建。
foreach(var method in methods)
中的一段代码来测试单个方法。 - CSDev我建议使用 .NET Compiler Platform SDK
来创建自己的规则。你可以在 这里 找到安装指南。
你可能会在安装过程中遇到一些问题,解决方案在 这里stackoverflow上。
完成后
PlatformNotSupportedExceptionAnalyzer
。PlatformNotSupportedExceptionAnalyzer
之外的所有项目。PlatformNotSupportedExceptionAnalyzer
中删除 .cs 和 .resx 文件。Analyze
r。using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
// ...
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class Analyzer : DiagnosticAnalyzer
{
private static readonly string typeName =
typeof(System.PlatformNotSupportedException).FullName;
private static readonly DiagnosticDescriptor rule =
new DiagnosticDescriptor(id: "ThrowsPlatformNotSupportedException",
title: "Throws 'PlatformNotSupportedException'",
messageFormat: "Do not throw 'PlatformNotSupportedException'",
category: "Usage",
defaultSeverity: DiagnosticSeverity.Error,
isEnabledByDefault: true,
description: "Throws 'PlatformNotSupportedException'");
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
ImmutableArray.Create(rule);
public override void Initialize(AnalysisContext context) =>
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.ThrowStatement);
private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
if (!(context.Node.ChildNodes().SingleOrDefault() is ObjectCreationExpressionSyntax node))
return;
var type = context.SemanticModel.GetTypeInfo(node).Type;
if ($"{type.ContainingNamespace}.{type.Name}".Equals(typeName))
context.ReportDiagnostic(Diagnostic.Create(rule, context.Node.GetLocation()));
}
}
测试它:
PlatformNotSupportedExceptionAnalyzer
的 \bin\Debug
文件夹。 AnalyzerSource
并保存。 AnalyzerSource
PlatformNotSupportedExceptionAnalyzer
并安装它。现在尝试:
throw new PlatformNotSupportedException();
收到错误:
你可以使用抛出错误ThrowsPlatformNotSupportedException 不要抛出 'PlatformNotSupportedException'
#pragma warning disable
和#pragma warning restore
来控制它,就像这样:
或者使用SuppressMessageAttribute
,像这样:
您还可以在“解决方案资源管理器 -> 项目 -> 引用 -> 分析器 -> 您的分析器”中更改其严重性。
PlatformNotSupportedException
的可能性(https://dev59.com/QrXna4cB1Zd3GeqPLXlz#57441394)。 - CSDev