Skip to content
Development
Skill

/csharp-refactoring

Safely refactors C#/.NET code without changing behavior. USE FOR any request to refactor, rename, move, extract, inline, merge, consolidate, deduplicate, split, or modernize C# code, including partial/generated declarations, wrappers, public APIs,

From plugin
skills
5.8k106 skills20 agents

Claude Code

$ npx -y skills add dotnet/skills --skill csharp-refactoring --agent claude-code

SKILL.md

csharp-refactoring.SKILL.md
name: csharp-refactoring
description: "Safely refactors C#/.NET code without changing behavior. USE FOR any request to refactor, rename, move, extract, inline, merge, consolidate, deduplicate, split, or modernize C# code, even a small extract, inline, or rename, or merging near-identical types; green builds miss drift in #if branches, generated partials, and reflection/config names. When a changed member is visible outside the assembly (PublicAPI.*.txt, InternalsVisibleTo, shipped package), also invoke dotnet-breaking-changes; local/private renames do not need it. Also use when a request calls a feature, bug fix, package/framework upgrade, or public nullability change a refactor and the behavior-changing part must be separated or declined. DO NOT USE FOR ordinary feature or bug fixes not presented as refactoring; standalone upgrades after reclassification (use dotnet-upgrade); adding tests; or formatting-only work."
license: MIT

C# Refactoring (behavior-preserving)

A refactor changes **structure**, never observable **behavior**. Do the edit with binding-aware tools, then confirm behavior held with a build + the relevant tests. Keep the effort proportional to the change: a one-line local rename does not need the ceremony a public multi-targeted change does.

Mandatory gate: classify before validation or editing

Read only enough repository context to classify **each requested operation**. Do this before restoring, building, or making an edit. Classification precedence is:

  • If the request explicitly asks for at least one separable behavior-preserving operation, complete

that structural work and defer only the behavior-changing or contract-changing operations. Do not invent or infer structural work to avoid the stop response.

  • If the structural and behavior-changing parts cannot be separated, use the whole-request stop

response and state why they are inseparable.

  • Otherwise, use the whole-request stop response only when **every** requested operation is outside

behavior-preserving refactoring.

For a whole request that is outside behavior-preserving refactoring:

1. State: `Not a behavior-preserving refactor: <specific reason>.` 2. State: `No files changed.` 3. State: `Next workflow: <workflow>.` Then stop. Do not add manual implementation steps, alternatives, an offer to proceed without the workflow, or a follow-up question — even when that workflow is unavailable.

| Requested as a "refactor" | Classification and action | |---|---| | Framework or NuGet version change | **Upgrade.** Do not edit or validate the upgrade here; hand off to `dotnet-upgrade`. | | New capability, flag, endpoint, tier, or behavior | **Feature.** Do not implement it here; hand off to the repository's feature workflow. | | Threshold, rate, output, or bug-result change | **Behavior change.** Defer it and hand off to the repository's bug-fix or behavior-change workflow; still complete any clearly separable structural operation. | | Tighten or loosen a shipped/public nullable annotation | **Source-contract change.** Leave the declaration and API record unchanged; hand off to the `dotnet-breaking-changes` skill. |

For a mixed request, never stop after classification. Perform the separable structural operation, explicitly defer the behavior/contract change, and never state `No files changed.` after completing structural work. Never modify tests to make an unauthorized behavior change appear preserved.

Work only in the current workspace

Use the current agent workspace as the boundary. If it is a Git checkout, resolve its repository root (`git rev-parse --show-toplevel`) and stay inside it. If Git metadata is absent, treat the current working directory and its subdirectories as the boundary, and use a solution or project named in the request inside it; Git is not a prerequisite for a refactor. Resolve prompt-provided relative paths inside that boundary.

Search and edit only that workspace. Never use filesystem-wide search or select a similarly named clone, another worktree, build output, or unrelated temporary directory because a file also exists there. If a named path is absent, stop and report the mismatch instead of guessing another workspace. If a tool rejects an in-workspace path for a mechanical reason such as path form or unsupported tool root, retry through another in-workspace mechanism. If the rejection is a permission or policy denial, report it instead of working around it. Never search outside the boundary.

Rename / move by bindings, not text

The #1 way a "rename" silently corrupts code is editing textual matches (comments, strings, unrelated overloads) instead of real **bindings**. Find every binding reference first, then edit semantically. Use the strongest tool available: an IDE/Roslyn workspace refactoring, then the C# LSP the [`dotnet` plugin declares](https://github.com/dotnet/skills/blob/main/plugins/dotnet/lsp.json) (`findReferences`, `goToDefinition`, `incomingCalls`, `rename` code action), then analyzer code-fixes / Roslynator, then compiler-validated edits (edit the true bindings, rebuild, let the compiler flag misses). Plain find/replace only when scope is provably tiny and every hit is verified. Include **every** `partial` declaration, and edit the generator input, never generated (`*.g.cs`) output.

For the operation → Roslyn-provider mapping and representative PRs, see [references/operation-catalog.md](references/operation-catalog.md).

Consolidate toward the existing source of truth

When de-duplicating, preserve the ownership direction stated by the code or request. If `B` duplicates an implementation already owned by `A`, keep `A` canonical and make `B` delegate to it; do not invert the dependency merely because either direction compiles. Preserve public compatibility wrappers when the duplicate surface is shipped, and migrate only in-repo callers that are safe to move.

Decisions that change the edit

Use the first matching row instead of applyi

Read more
@dotnet
Ships withskills

This repository contains the .NET team's curated set of portable skills and host-specific custom agents for coding agents. For information about the Agent Skills standard, see agentskills.io.

5.8k106 skills20 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
5.8k
Star history of dotnet/skills on GitHub, a chart by star-history.com

Other skills on skills.

csharp-scripts

csharp-scripts

Run file-based C# apps with the .NET CLI when the user explicitly wants C#/.NET code without creating a project. Use for C#…

@dotnet@dotnetInstall Skill
dotnet-pinvoke

dotnet-pinvoke

Correctly call native (C/C++) libraries from .NET using P/Invoke and LibraryImport. Covers function signatures, string…

@dotnet@dotnetInstall Skill
nuget-trusted-publishing

nuget-trusted-publishi…

Set up NuGet trusted publishing (OIDC) on a GitHub Actions repo — replaces long-lived API keys with short-lived tokens. USE FOR:…

@dotnet@dotnetInstall Skill
vectorization

vectorization

Design, implement, optimize, and review SIMD code in .NET. USE FOR: vectorizing scalar loops with TensorPrimitives,…

@dotnet@dotnetInstall Skill
technology-selection

technology-selection

Guides technology selection and implementation of AI and ML features in .NET 8+ applications using ML.NET,…

@dotnet@dotnetInstall Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about csharp-refactoring.

Which coding agents can use csharp-refactoring?
csharp-refactoring installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.