| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot introduce the indexer "<Indexer>" into type "<TargetType>" because the DefaultMemberAttribute of the type names another member, "<DefaultMember>", and the OverrideAction of the introduction is "<OverrideAction>". Give the introduced indexer the name "<DefaultMember>" with IndexerNameAttribute, or set OverrideAction to Ignore. |
Cause
In .NET, an indexer is a property with parameters, and a type makes its indexers usable as indexers with DefaultMemberAttribute, which names the property. All the indexers of a type must have the same name. The C# compiler names them Item, or the name given by IndexerNameAttribute, and adds the DefaultMemberAttribute itself.
When an aspect introduces an indexer with IntroduceMemberAttribute and the target type already has a DefaultMemberAttribute that names another member, PostSharp cannot make the introduced indexer an indexer of the type. When the OverrideAction of the introduction is Fail, the default, or OverrideOrFail, PostSharp reports LA0089 on the indexer of the aspect.
<OverrideAction> shows Default for Fail, because both names have the same value.
In the following example, the [Metadata] aspect introduces an indexer named Item into Document, whose indexer is named Line.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0089_Error;
[PSerializable]
public class MetadataAttribute : InstanceLevelAspect
{
[PNonSerialized]
private Dictionary<string, string> values = new();
// The introduced indexer is named Item, but Document names its indexer Line.
[IntroduceMember]
public string this[ string key ]
{
get => this.values.TryGetValue( key, out var value ) ? value : "(none)";
set => this.values[key] = value;
}
public override void RuntimeInitializeInstance()
{
this.values = new Dictionary<string, string>();
}
}
[Metadata]
public class Document
{
private readonly string[] lines = { "First line", "Second line" };
[IndexerName( "Line" )]
public string this[ int index ] => this.lines[index];
}
public static class Program
{
public static void Main()
{
var document = new Document();
Console.WriteLine( document[0] );
// The indexer introduced into Document is not visible at compile time, so it is called with the dynamic keyword.
dynamic metadata = document;
metadata["Author"] = "Alice";
Console.WriteLine( metadata["Author"] );
}
}
error LA0089: LA0089_Error.cs(18,19): Cannot introduce the indexer "Item" into type "Errors.LA0089_Error.Document" because the DefaultMemberAttribute of the type names another member, "Line", and the OverrideAction of the introduction is "Default". Give the introduced indexer the name "Line" with IndexerNameAttribute, or set OverrideAction to Ignore.
Resolution
- Give the introduced indexer the name of the indexers of the target type, with IndexerNameAttribute on the indexer of the aspect.
- Otherwise, set the OverrideAction of the introduction to Ignore or OverrideOrIgnore: PostSharp then skips the introduction of the indexer in this type.
In the following example, the indexer of the aspect is named Line, so that Document has two indexers with this name.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0089_Fixed;
[PSerializable]
public class MetadataAttribute : InstanceLevelAspect
{
[PNonSerialized]
private Dictionary<string, string> values = new();
// The introduced indexer has the same name as the indexer of Document.
[IntroduceMember]
[IndexerName( "Line" )]
public string this[ string key ]
{
get => this.values.TryGetValue( key, out var value ) ? value : "(none)";
set => this.values[key] = value;
}
public override void RuntimeInitializeInstance()
{
this.values = new Dictionary<string, string>();
}
}
[Metadata]
public class Document
{
private readonly string[] lines = { "First line", "Second line" };
[IndexerName( "Line" )]
public string this[ int index ] => this.lines[index];
}
public static class Program
{
public static void Main()
{
var document = new Document();
Console.WriteLine( document[0] );
// The indexer introduced into Document is not visible at compile time, so it is called with the dynamic keyword.
dynamic metadata = document;
metadata["Author"] = "Alice";
Console.WriteLine( metadata["Author"] );
}
}
First line
Alice
See Also
Reference
IntroduceMemberAttribute
MemberOverrideAction
IndexerNameAttribute
DefaultMemberAttribute
Other Resources
Introducing Interfaces, Methods, Properties and Events into Existing Classes