Skip to main content

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):

  1. extern: "The implementation is located externally, usually in a DLL or unmanaged code."
  2. 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

  • extern is used primarily for P/Invoke (Platform Invocation Services). It tells the runtime to load a non-.NET library (like kernel32.dll) and find the function entry point there.
  • abstract is 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.

  1. Is it in a DLL? Use extern (and remove abstract).
  2. Is it in a Subclass? Use abstract (and remove extern).
  3. Do you need both? Use the Wrapper Pattern. Define a concrete class containing the extern method, and implement an interface or abstract base class that calls it.