How to Resolve Error "CS0646: Cannot specify the DefaultMember attribute on a type containing an indexer" in C#
The Compiler Error CS0646 is a redundancy error related to class metadata. The message reads: "Cannot specify the DefaultMember attribute on a type containing an indexer".
In the .NET Framework, a class can have a "Default Member," which allows instances of that class to be accessed using array syntax (e.g., myObject[0]). In C#, this concept is exposed via the Indexer syntax (this[...]). When you define an indexer, the C# compiler automatically adds the [DefaultMember] attribute to the class IL code for you (usually naming the member "Item").
This error occurs when you manually add the [DefaultMember] attribute to a class that already has a C# indexer defined. The compiler views this as a conflict because it is trying to set the default member automatically, and you are trying to set it manually.
Understanding Indexers and Default Members
Under the hood, the Common Language Runtime (CLR) does not have a specific "Indexer" concept. Instead, it relies on:
- A property (usually named
Item) that accepts arguments. - A class-level attribute
[DefaultMember("Item")]pointing to that property.
When you write this in C#:
public int this[int index] { get { ... } }
The compiler automatically generates both the Property named Item and the DefaultMember attribute. If you try to add the attribute yourself, you are fighting the compiler.
Scenario: The Attribute Conflict
This error often happens when porting code from languages that require explicit attributes (like VB.NET) or when a developer tries to customize the internal name of the indexer using the wrong attribute.
Example of error:
using System.Reflection;
// ⛔️ Error CS0646: Cannot specify the DefaultMember attribute on a type
// containing an indexer.
[DefaultMember("MyCollectionItem")]
public class DataStore
{
private string[] _data = new string[10];
// The definition of 'this' implicitly generates [DefaultMember("Item")]
public string this[int index]
{
get => _data[index];
set => _data[index] = value;
}
}
Solution 1: Remove the Attribute (Standard Fix)
In C#, the indexer syntax is the preferred way to define the default member. Unless you have a very specific interoperability requirement, you should simply remove the manual attribute and let the compiler handle it.
Solution:
// ✅ Correct: Attribute removed.
public class DataStore
{
private string[] _data = new string[10];
public string this[int index]
{
get => _data[index];
set => _data[index] = value;
}
}
Solution 2: Renaming the Indexer
If your goal in using [DefaultMember] was to change the internal name of the indexer property (e.g., you want it to be compiled as MyObject.Value instead of MyObject.Item for other languages to consume), you should use the [IndexerName] attribute instead.
This attribute is specifically designed to work with indexers, whereas [DefaultMember] conflicts with them.
Solution:
using System.Runtime.CompilerServices; // Required for IndexerName
public class DataStore
{
private string[] _data = new string[10];
// ✅ Correct: Using IndexerName changes the compiled name to "MyItem"
// and updates the automatic DefaultMember attribute to match.
[IndexerName("MyItem")]
public string this[int index]
{
get => _data[index];
set => _data[index] = value;
}
}
Why rename an indexer?
In C#, you always use obj[0], so the name doesn't matter. However, languages that don't support indexer syntax directly might need to call the property by name, e.g., obj.get_MyItem(0).
Conclusion
CS0646 is a redundancy check.
- Identify the Conflict: You have both
[DefaultMember]andthis[...]in the same class. - Standard C#: Delete the
[DefaultMember]attribute. - Custom Naming: If you need to rename the underlying property, use
[IndexerName]on the indexer property itself, not[DefaultMember]on the class.