How to Resolve Error "CS0180: 'member' cannot be both extern and abstract" in C#
The Compiler Error CS0180 is a logical contradiction error. The message reads: "'MemberName' cannot be both extern and abstract".
To understand this error, you must look at what these two keywords tell the compiler about the location of the method's implementation (the code body):
extern: "The implementation is located externally, usually in a DLL or unmanaged code."abstract: "The implementation is missing here and must be provided by a derived class."
A method cannot simultaneously exist in an external DLL and wait for a child class to define it. You must choose one mechanism or the other.
Understanding the Conflict
externis used primarily for P/Invoke (Platform Invocation Services). It tells the runtime to load a non-.NET library (likekernel32.dll) and find the function entry point there.abstractis used for Inheritance. It tells the runtime that the logic will be supplied by a subclass.
You cannot delegate the implementation to the Operating System (extern) and the Inheritance Chain (abstract) at the same time.
Scenario: The Impossible Definition
This error often occurs when a developer wants to create a base class that wraps native Windows API calls but tries to mark the API definition itself as abstract to enforce some design pattern.
Example of error:
using System.Runtime.InteropServices;\
public abstract class DeviceDriver
{
// ⛔️ Error CS0180: 'Beep' cannot be both extern and abstract.
// You cannot tell the compiler to look in "user32.dll" AND look in a subclass.
[DllImport("user32.dll")]
public abstract extern bool MessageBeep(uint uType);
}
Solution 1: Use extern (Platform Invocation)
If your goal is to call a native function (like a Windows API), remove the abstract keyword. extern methods act as the definition themselves; they do not need to be overridden. They are typically marked static.
Solution:
using System.Runtime.InteropServices;
public class DeviceDriver
{
// ✅ Correct: 'static extern' defines a P/Invoke call.
[DllImport("user32.dll")]
public static extern bool MessageBeep(uint uType);
}
Solution 2: Use abstract (Polymorphism)
If your goal is to define a blueprint that child classes must implement, remove the extern keyword (and any [DllImport] attributes).
Solution:
public abstract class SoundPlayer
{
// ✅ Correct: Pure C# abstraction.
// Subclasses will provide the C# logic.
public abstract void PlaySound(string file);
}
Advanced: Abstraction over Native Code
If you are trying to create an abstract interface for Native Code (e.g., so you can unit test your application without calling actual Windows APIs), you should wrap the extern call inside a standard method.
Do not try to make the extern method itself abstract. Instead, implement an abstract method that calls the extern method (or an interface).
Pattern: The Wrapper
using System.Runtime.InteropServices;
// 1. Define the Contract
public interface INativeWrapper
{
void Beep();
}
// 2. Implement the Real Native Call
public class WindowsAudio : INativeWrapper
{
// The private extern definition
[DllImport("user32.dll")]
private static extern bool MessageBeep(uint uType);
// The public implementation matching the interface
public void Beep()
{
MessageBeep(0);
}
}
// 3. Implement a Mock for Testing
public class MockAudio : INativeWrapper
{
public void Beep()
{
System.Console.WriteLine("[Mock] Beep!");
}
}
Conclusion
CS0180 forces you to decide where the code lives.
- Is it in a DLL? Use
extern(and removeabstract). - Is it in a Subclass? Use
abstract(and removeextern). - Do you need both? Use the Wrapper Pattern. Define a concrete class containing the
externmethod, and implement an interface or abstract base class that calls it.