Skip to main content

How to Resolve Error "CS0669: A class with the ComImport attribute cannot have a user-defined constructor" in C#

The Compiler Error CS0669 is a restriction related to COM Interoperability (interacting with legacy unmanaged code). The message reads: "A class with the ComImport attribute cannot have a user-defined constructor".

When you mark a class with the [ComImport] attribute, you are telling the C# compiler: "This class implementation is not defined here. It is defined in an external COM library (like a C++ DLL), and the .NET Runtime handles creating instances of it."

Because the Common Language Runtime (CLR) takes full control over instantiating these objects (via CoCreateInstance and Runtime Callable Wrappers), any C# constructor logic you write would be bypassed or invalid. Therefore, the compiler forbids user-defined constructors in these classes.

Understanding ComImport and Instantiation

The [ComImport] attribute is applied to a class to define a COM Class (CoClass) within managed code. This is usually accompanied by a [Guid("...")] attribute.

When you write var obj = new MyComClass();, the compiler does not execute a C# constructor. Instead, it emits instructions to the runtime to:

  1. Look up the GUID associated with the class.
  2. Ask the Operating System (COM) to create an instance of that object.
  3. Wrap that unmanaged object in a standard .NET wrapper (RCW).

Since the creation logic happens inside the Windows OS, there is no place for your C# constructor code to run.

Scenario: The Invalid Constructor

This error occurs when you define a COM import class but try to add initialization logic (like logging or setting properties) inside a standard C# constructor.

Example of error:

using System;
using System.Runtime.InteropServices;

// Simulating a COM object definition
[ComImport]
[Guid("00000000-0000-0000-0000-000000000001")] // Example GUID
public class LegacyComObject
{
// ⛔️ Error CS0669: A class with the ComImport attribute
// cannot have a user-defined constructor.
// The runtime builds this object, not this code.
public LegacyComObject()
{
Console.WriteLine("Initializing COM object...");
}
}

Solution 1: Remove the Constructor (Let the Runtime Handle It)

If you just want to define the class so you can use it in C#, you must simply remove the constructor. The C# compiler will automatically generate a parameterless "dummy" constructor that allows you to write new LegacyComObject() elsewhere in your code, which triggers the COM activation logic.

Solution:

using System.Runtime.InteropServices;

[ComImport]
[Guid("00000000-0000-0000-0000-000000000001")]
public class LegacyComObject
{
// ✅ Correct: No constructor definition.
// The class body is usually empty or contains method signatures mapped to the COM interface.
}

public class Program
{
static void Main()
{
// This is valid. The runtime intercepts this 'new' call
// and activates the COM object via the GUID.
var comObj = new LegacyComObject();
}
}
note

Usually, [ComImport] classes are generated automatically by tools like TlbImp.exe (Type Library Importer) or Visual Studio when adding a COM Reference. You rarely need to write them by hand.

Solution 2: Use a Wrapper Class for Initialization Logic

If you specifically need to run C# code immediately after the COM object is created (e.g., to configure settings or log activity), you cannot put that logic in the [ComImport] class.

Instead, create a standard C# class that wraps or inherits (if applicable via interfaces) the usage of the COM object.

Solution: Factory Pattern

using System.Runtime.InteropServices;

// 1. The Raw COM Import (No constructor)
[ComImport]
[Guid("00000000-0000-0000-0000-000000000001")]
public class LegacyComObject
{
}

// 2. A Wrapper to handle initialization
public class LegacyWrapper
{
public LegacyComObject ComInstance { get; private set; }

public LegacyWrapper()
{
// ✅ Correct: Initialize the COM object here
ComInstance = new LegacyComObject();

// Perform your custom logic
InitializeCustomSettings();
}

private void InitializeCustomSettings()
{
System.Console.WriteLine("Wrapper initialized and COM object created.");
}
}

Conclusion

CS0669 enforces the rules of COM Interop.

  1. Understand the Source: [ComImport] means the object is defined externally (in Windows/COM), not in your C# code.
  2. Remove Logic: You cannot inject C# logic into the instantiation process of a raw COM object. Delete the constructor.
  3. Wrap It: If you need initialization logic, create a separate C# class that creates the COM object and then runs your code.