用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/rudironsoni/Synaxis --skill dotnet-library-api-compat命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
AI-powered wiki generation for code repositories with commands, agents, and skills
Routes .NET/C# work to domain skills. Loads coding-standards for code paths.
Skill manifest management for dotnet-agent-harness. Tracks skill dependencies, conflicts, version compatibility, and provides validation and resolution tools. Triggers on: skill manifest, dependency resolution, skill compatibility, version conflicts, build manifest, validate dependencies.
基于 SOC 职业分类
正在显示 SKILL.md
| name | dotnet-library-api-compat |
| description | Maintains library compatibility. Binary/source compat rules, type forwarders, SemVer impact. |
Binary and source compatibility rules for .NET library authors. Covers which API changes break consumers at the binary level (assembly loading, JIT resolution) versus at the source level (compilation), how to use type forwarders for assembly reorganization without breaking consumers, and how versioning decisions map to SemVer major/minor/patch increments.
Version assumptions: .NET 8.0+ baseline. Compatibility rules apply to all .NET versions but examples target modern SDK-style projects.
Cross-references: [skill:dotnet-api-versioning] for HTTP API versioning, [skill:dotnet-nuget-authoring] for NuGet packaging and SemVer rules, [skill:dotnet-multi-targeting] for multi-TFM packaging and ApiCompat tooling.
Binary compatibility means existing compiled assemblies continue to work at runtime without recompilation. A
binary-breaking change causes TypeLoadException, MissingMethodException, MissingFieldException, or
TypeInitializationException at runtime.
| Change | Why Safe |
|---|---|
| Add new public type | Existing code never references it |
| Add new public method to non-sealed class | Existing call sites resolve to their original overload |
| Add new overload with different parameter count | Existing binaries bind to the original method token |
| Add optional parameter to existing method | Callers compiled against the old signature have default values embedded in their IL; the runtime resolves the same method token regardless of whether the optional parameter is supplied |
Widen access modifier (protected to public) | Existing references remain valid at higher visibility |
| Add non-abstract interface member with default implementation | Existing implementors inherit the default; no TypeLoadException |
Remove sealed from class | Removes a restriction; existing code never subclassed it |
Add new enum member | Existing binaries that switch on the enum simply fall through to default |
| Change | Runtime Failure | Example |
|---|---|---|
| Remove public type | TypeLoadException | Delete public class Widget |
| Remove public method | MissingMethodException | Remove Widget.Calculate() |
| Change method return type | MissingMethodException | int Calculate() to long Calculate() |
| Change method parameter types | MissingMethodException | void Process(int id) to void Process(long id) |
| Change field type | MissingFieldException | public int Count to public long Count |
| Reorder struct fields | Memory layout change | Breaks interop and Unsafe.As<> consumers |
| Add abstract member to public class | TypeLoadException | Existing subclasses lack the implementation |
| Add interface member without default implementation | TypeLoadException | Existing implementors lack the member |
Change virtual method to non-virtual | MissingMethodException for overriders | Overriders compiled expecting virtual dispatch |
| Seal a previously unsealed class | TypeLoadException | Existing subclasses cannot load |
| Change namespace of public type | TypeLoadException | Unless a type forwarder is added (see below) |
Remove virtual from a method | MissingMethodException | Consumers compiled with callvirt find no virtual slot |
Default interface members (DIM) added in C# 8 allow adding members to interfaces without breaking existing implementors -- but only at the binary level:
public interface IWidget
{
string Name { get; }
// Binary-safe: existing implementors inherit this default
string DisplayName => Name.ToUpperInvariant();
}
```text
However, if a consumer explicitly casts to the interface and the runtime cannot find the default implementation (older
runtime), this fails. All runtimes in the .NET 8.0+ baseline support DIMs.
---
## Source Compatibility
Source compatibility means existing consumer code continues to compile without changes. A source-breaking change causes
compiler errors or changes behavior silently (which is worse).
### Common Source-Breaking Changes
| Change | Compiler Impact | Example |
| -------------------------------------------------------- | ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| Add overload causing ambiguity | CS0121 (ambiguous call) | Add `Process(long id)` when `Process(int id)` exists; callers passing `int` literal now have two candidates |
| Add extension method conflicting with instance method | New extension hides or conflicts | Adding `Where()` extension in a namespace the consumer |
| | | ` ( = )` to `` -- recompiled callers |
| { }
{ }
```text
This **source-breaking** (callers silently rebind) but **binary-compatible** (old compiled code still calls the
`` overload token).
**Mitigation:** When adding overloads to APIs, prefer parameter types that create conversion
paths existing parameter types. Use `[EditorBrowsable(EditorBrowsableState.Never)]` compatibility shims that
must remain binary compatibility but should appear IntelliSense.
Extension methods resolve at compile time based imported namespaces. Adding a extension method can shadow an
existing instance method conflict extensions other libraries:
```csharp
{
=>
s.Length <= maxLength ? s : s[..maxLength];
}
```text
**Mitigation:** Keep extension methods the same .
.
---
##
.
.
###
- ** ** ,
- ** **
- ** **
- ** **
###
** ** ( ),
:
```
;
[]
[]
[]
```text
The original assembly must reference the destination assembly so that `()` resolves correctly.
The **destination assembly** (the one types are moving TO) contains the actual type definitions. No special attributes
are needed the destination side. The `[TypeForwardedFrom]` attribute optional metadata that records the type
originally lived -- useful serialization compatibility:
```csharp
System.Runtime.CompilerServices;
;
[]
{
Name { ; ; } = .Empty;
Price { ; ; }
}
```text
`[TypeForwardedFrom]` critical types deserialized `BinaryFormatter`, `DataContractSerializer`, any
serializer that encodes assembly-qualified type names. Without it, deserialization of data written older versions
will fail `TypeLoadException`.
Type forwarders can chain: Assembly A forwards to Assembly B, which forwards to Assembly C. The runtime follows the
chain. However, =>
<PropertyGroup>
<TargetFrameworks>net8;netstandard2</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include= />
</ItemGroup>
</Project>
```csharp
See [skill:dotnet-multi-targeting] multi-TFM packaging mechanics [skill:dotnet-nuget-authoring] NuGet
packaging of forwarding shims.
---
Map API changes to Semantic Versioning increments. For full SemVer rules NuGet versioning strategies, see
[].
| Change Category | SemVer | Reason |
| ------------------------------------------------- | --------- | ----------------------------------------------------- |
| Remove type member | **Major** | Binary-breaking |
| ; signals deprecation |
| Add type | **Minor** | Additive, no breaking impact |
| ; source impact accepted at minor |
| Add optional parameter | **Minor** | Binary-compatible; recompilation picks up |
| Add DIM to | **** | -; additive |
| Change | **** | - |
| | **** | -; additive |
| Bug fix no API change | **Patch** | No API impact |
| Documentation metadata-only change | **Patch** | No API impact |
| Performance improvement same API | **Patch** | No API impact |
The standard workflow removing API members across major versions:
| Release | Action | Effect |
| ------------ | --------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
| v2 (Minor) | Add `[Obsolete()]` | Compiler warning CS0618; existing code compiles runs |
| v2 (Minor) | Change to `[Obsolete(, error: )]` | Compiler error CS0619; ; consumers must migrate |
```csharp
[]
=> CalculateAsync().GetAwaiter().GetResult();
[]
=> CalculateAsync().GetAwaiter().GetResult();
```text
Always include the replacement API the planned removal version the obsolete message so both humans agents can
migrate proactively.
Adding removing target frameworks affects binary compatibility consumers:
- **Adding a TFM** (e.g., adding `net9` to an existing `net8` package): **Minor** version bump. Existing
consumers `net8` are unaffected; consumers `net9` gain optimized code paths.
- **Removing a TFM** (e.g., dropping `netstandard2`): **Major** version bump. Consumers targeting the removed TFM can
no longer resolve a compatible assembly.
- **Changing the lowest supported TFM** (e.g., `net6` to `net8`): **Major** version bump. Consumers the dropped
TFM lose compatibility.
See [skill:dotnet-multi-targeting] practical guidance managing TFM additions removals.
---
Use `EnablePackageValidation` your `.csproj` to automatically compare the current build against the previously
shipped package detect binary/source-breaking changes:
```xml
<PropertyGroup>
<EnablePackageValidation></EnablePackageValidation>
<!-- Compare against the last shipped version -->
<PackageValidationBaselineVersion></PackageValidationBaselineVersion>
</PropertyGroup>
```text
Build output flags breaking changes:
```text
error CP0002: Member was removed
error CP0006: Cannot change type of
```text
To suppress known intentional breaks, generate a suppression :
```bash
dotnet pack /p:GenerateCompatibilitySuppressionFile=
```bash
This produces a `CompatibilitySuppressions.xml` that can be checked . If unspecified, the SDK reads
`CompatibilitySuppressions.xml` the project directory automatically. To specify suppression files:
```xml
<ItemGroup>
<ApiCompatSuppressionFile Include= />
</ItemGroup>
```xml
Note: `ApiCompatSuppressionFile` an **ItemGroup item**, a PropertyGroup property. Multiple suppression files can
be included.
For deeper API surface tracking PublicApiAnalyzers CI enforcement workflows, see
[].
---
**Do assume adding an overload always safe** -- it binary-compatible but can be source-breaking due to
overload resolution changes. Always check conversion paths between existing parameter types.
**Do members without a major version bump** -- even `[Obsolete]` members must be preserved until
the next major version to maintain binary compatibility.
**Do forget type forwarders moving types between assemblies** -- without `[TypeForwardedTo]`, consumers
`TypeLoadException` at runtime. Always forwarders the original assembly.
**Do change `optional` parameter values patch releases** -- silently changes behavior
recompiled consumers old binaries retain the old , creating version-dependent behavior divergence.
**Do confuse binary compatibility source compatibility** -- a change can be binary-safe but source-breaking
( overload) source-safe but binary-breaking (changing type `` to ``). Test both.
**Do skip `[TypeForwardedFrom]` serializable types** -- serializers that encode assembly-