A Visual Studio 2022 extension that extracts interfaces from C# classes and records with interactive member selection and customizable options.
✨ Right-click to extract - Works directly from Solution Explorer context menu
✨ Interactive selection - Choose which methods, properties, events, and indexers to include
✨ Preview before saving - Review generated interface before writing to disk
✨ Smart defaults - Auto-suggests interface names with configurable prefix
✨ Batch processing - Handle multiple files at once
✨ Partial class support - Analyzes all parts of partial classes automatically
✨ Record support - Works with both classes and records
✨ Implementation stubs - Generate skeleton implementation classes
✨ Internal members - Optionally include internal members
✨ XML documentation - Preserves XML comments from original members
✨ Generic support - Correctly handles generic methods with constraints
✨ Read-only properties - Properly detects { get; } vs { get; set; }
✨ Overwrite protection - Prompts before replacing existing files
✨ Detailed logging - Progress tracking in Output Window
✨ Customizable options - Configure behavior through Tools → Options
✨ Operator overloads - Optional support for operator methods
✨ Template system - Custom headers, sorting, and grouping
- Public classes (including partial classes)
- Public records
- Internal classes/records (optional)
- Public methods (including generic methods with constraints)
- Public properties (with correct accessor detection)
- Public events
- Public indexers
- Public operator overloads (optional - disabled by default)
- Conversion operators (implicit/explicit)
- Internal members (optional - disabled by default)
Note: Static members and private members are excluded by design.
- Visual Studio 2022 (Community, Professional, or Enterprise)
- .NET Framework 4.8
- Install the Visual Studio extension development workload via Visual Studio Installer
- Clone or download this repository
- Open
InterfaceExtractor.slnin Visual Studio 2022 - Build the solution (Ctrl+Shift+B)
- Close all Visual Studio instances
- Run the generated
.vsixfile frombin/Debug/orbin/Release/ - Restart Visual Studio
- Download the
.vsixfile - Close all Visual Studio instances
- Double-click the
.vsixfile - Follow the installation wizard
- Restart Visual Studio
Access settings through Tools → Options → Interface Extractor → General
| Setting | Default | Description |
|---|---|---|
| Interface Folder Name | Interfaces |
Folder for generated interface files |
| Interface Prefix | I |
Suggested prefix for interface names |
| Namespace Suffix | .Interfaces |
Appended to original namespace |
| Setting | Default | Description |
|---|---|---|
| Automatically Update Class | true |
Add interface to class declaration |
| Add Using Directive | true |
Include using for interface namespace |
| Warn If No 'I' Prefix | true |
Show warning if name lacks 'I' prefix |
| Include Operator Overloads | false |
Extract operator overloads |
| Show Preview Before Saving | true |
Display preview dialog before saving |
| Include Internal Members | false |
Include internal members in extraction |
| Analyze Partial Classes | true |
Scan all partial files for members |
| Setting | Default | Description |
|---|---|---|
| Generate Implementation Stubs | false |
Create skeleton implementation class |
| Implementation Stub Suffix | Implementation |
Suffix for stub class names |
| Setting | Default | Description |
|---|---|---|
| Include File Header | false |
Add header comment to files |
| File Header Template | See below | Template for file headers |
| Member Separator Lines | 1 |
Blank lines between members (0-3) |
| Sort Members | false |
Sort alphabetically by type/name |
| Group By Member Type | false |
Group by Properties, Methods, etc. |
Default File Header Template:
// Generated by Interface Extractor on {Date} at {Time}
// File: {FileName}
Placeholders: {FileName}, {Date}, {Time}
- Right-click any
.csfile in Solution Explorer - Select Extract Interface...
- Review/edit the interface name (defaults based on your prefix setting)
- Select members to include
- Click OK
- Preview the interface (if enabled)
- Click Save to create the file
The extension creates an interface file in your configured folder and optionally:
- Updates the class/record declaration to implement the interface
- Generates an implementation stub class (if enabled)
When Show Preview Before Saving is enabled:
- Review the complete generated interface code
- See the exact file path where it will be saved
- Click Save to proceed or Cancel to abort
- ✏️ Edit interface name - Modify the suggested name
- ☑️ Select/deselect members - Pick which members to include
- 🔘 Select All / Deselect All - Quick selection buttons
- 👁️ Preview signatures - See exact interface signatures
- Open Output Window (View → Output or Ctrl+Alt+O)
- Select Interface Extractor from the dropdown
- View detailed logs of the extraction process
Input (BookingData.cs):
namespace MyProject.Data
{
/// <summary>
/// Manages booking operations
/// </summary>
public class BookingData
{
/// <summary>
/// Gets a booking by ID
/// </summary>
public async Task<Booking> GetBookingAsync(Guid id) { }
/// <summary>
/// Gets or sets the booking name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets the booking date (read-only)
/// </summary>
public DateTime BookingDate { get; }
private void InternalMethod() { } // Excluded (private)
}
}Output (Interfaces/IBookingData.cs):
namespace MyProject.Data.Interfaces
{
/// <summary>
/// Manages booking operations
/// </summary>
public interface IBookingData
{
/// <summary>
/// Gets a booking by ID
/// </summary>
Task<Booking> GetBookingAsync(Guid id);
/// <summary>
/// Gets or sets the booking name
/// </summary>
string Name { get; set; }
/// <summary>
/// Gets the booking date (read-only)
/// </summary>
DateTime BookingDate { get; }
}
}Input:
public record Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
public DateTime BirthDate { get; init; }
public int Age => (DateTime.Now - BirthDate).Days / 365;
public string GetFullName() => $"{FirstName} {LastName}";
}Output:
public interface IPerson
{
string FirstName { get; }
string LastName { get; }
DateTime BirthDate { get; }
int Age { get; }
string GetFullName();
}Note: init accessors are converted to get for broader compatibility. While init is valid in C# 9+ interface declarations, implementing types must also use init accessors, which may not always be desirable.
Input - UserService.Part1.cs:
public partial class UserService
{
public User GetUser(int id) { }
public void UpdateUser(User user) { }
}Input - UserService.Part2.cs:
public partial class UserService
{
public List<User> GetAllUsers() { }
public void DeleteUser(int id) { }
}Output (combines both files):
public interface IUserService
{
User GetUser(int id);
void UpdateUser(User user);
List<User> GetAllUsers();
void DeleteUser(int id);
}When Generate Implementation Stubs is enabled:
Generated Interface (IBookingData.cs):
public interface IBookingData
{
Task<Booking> GetBookingAsync(Guid id);
string Name { get; set; }
}Generated Stub (BookingDataImplementation.cs):
namespace MyProject.Data
{
public class BookingDataImplementation : IBookingData
{
public Task<Booking> GetBookingAsync(Guid id)
{
throw new System.NotImplementedException();
}
public string Name { get; set; }
}
}With Include Internal Members enabled:
Input:
public class DataService
{
public void PublicMethod() { }
internal void InternalMethod() { }
private void PrivateMethod() { } // Still excluded
}Output:
public interface IDataService
{
void PublicMethod();
void InternalMethod(); // Included when option is enabled
}- Verify you're right-clicking
.csfiles - Check Extensions → Manage Extensions to confirm it's installed and enabled
- Restart Visual Studio
- Ensure Visual Studio SDK is installed
- Restore NuGet packages (right-click solution → Restore NuGet Packages)
- Verify target framework is .NET Framework 4.8
- Check Output Window (View → Output) and select "Interface Extractor"
- Ensure the class/record is
public(orinternalif that option is enabled) - Verify the file contains valid C# syntax
- Check that at least one accessible member exists
- Ensure Analyze Partial Classes is enabled in options
- Verify all partial files are in the same project
- Check Output Window for partial file analysis logs
- Close and reopen Visual Studio after changing options
- Check Tools → Options → Interface Extractor → General
- Verify settings were saved (they should persist between sessions)
InterfaceExtractor/
├── Commands/
│ └── ExtractInterfaceCommand.cs # Command handler and orchestration
├── Services/
│ └── InterfaceExtractorService.cs # Roslyn-based extraction logic
├── Options/
│ └── OptionsPage.cs # Settings/configuration page
├── UI/
│ ├── ExtractInterfaceDialog.xaml # Member selection dialog
│ ├── ExtractInterfaceDialog.xaml.cs
│ ├── PreviewDialog.xaml # Interface preview dialog
│ ├── PreviewDialog.xaml.cs
│ ├── OverwriteDialog.xaml # File overwrite confirmation
│ ├── OverwriteDialog.xaml.cs
│ └── MemberSelectionItem.cs # View model for members
├── Constants.cs # Configuration constants
├── InterfaceExtractorPackage.cs # VS Package entry point
└── InterfaceExtractorPackage.vsct # Command definitions- Open
InterfaceExtractor.slnin Visual Studio 2022 - Press F5 to launch experimental instance
- Open a test project in the experimental instance
- Test the extension
- Check Output Window → "Interface Extractor" for logs
- Roslyn (Microsoft.CodeAnalysis) - C# syntax parsing and analysis
- Visual Studio SDK - IDE integration
- WPF - User interface dialogs
- VSIX - Extension packaging format
- Only processes public and optionally internal members (not private/protected)
- Nested classes: only processes top-level classes/records
- Operator overloads in interfaces: Only supported in C# 11+. Generated operator signatures in interfaces require manual addition of
static abstractkeywords, and the containing interface must support static abstract members.
See CHANGELOG.md for detailed version history and release notes.
MIT License
Copyright (c) 2025 Developer Chizaruu
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Contributions welcome! Areas for improvement:
- Custom template files (.tt or .scriban)
- Extract interface from multiple classes at once
- Integration with refactoring tools
- Performance optimizations
- Accessibility improvements
For issues or questions:
- Check the Output Window (View → Output → "Interface Extractor") for detailed error messages
- Review the Troubleshooting section above
- Check Tools → Options → Interface Extractor for configuration options
- Verify Visual Studio 2022 and .NET Framework 4.8 compatibility
- Create an issue with:
- Visual Studio version
- Extension version
- Steps to reproduce
- Output Window logs
- Sample code (if applicable)
- Current option settings
Made with ❤️ for Visual Studio developers