Open sandboxFocusImprove this doc

LA0060: Introduced Member Already Exists in the Target Type

Severity Error
Reported by PostSharp
Message Cannot introduce member "<Member>" into type "<TargetType>" because it is already defined in type "<DeclaringType>".

Cause

An aspect introduces a method, a property or an event into its target type with IntroduceMemberAttribute. When the target type already defines a member with the same name and signature, PostSharp follows the OverrideAction of the introduction. Its default value, Fail, reports LA0060 instead of replacing the existing member, so that the aspect does not silently change code that you wrote.

<DeclaringType> is the type that defines the existing member: the target type itself, or one of its base types.

In the following example, the [Describable] aspect introduces a Describe method into Customer, which already has one.

using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.LA0060_Error;

[PSerializable]
public class DescribableAttribute : InstanceLevelAspect
{
    [IntroduceMember]
    public string Describe() => $"Instance of {this.Instance!.GetType().Name}";
}

[Describable]
public class Customer
{
    public string Name { get; set; } = "Alice";

    // The aspect introduces a method with the same signature into this class.
    public string Describe() => $"Customer {this.Name}";
}

public static class Program
{
    public static void Main()
    {
        Console.WriteLine( new Customer().Describe() );
    }
}
error LA0060: LA0060_Error.cs(21,19): Cannot introduce member "Describe" into type "Errors.LA0060_Error.Customer" because it is already defined in type "Errors.LA0060_Error.Customer".

Resolution

Choose what the aspect does when the member already exists, with the OverrideAction property of the introduction:

  • Ignore keeps the existing member and skips the introduction.
  • OverrideOrFail replaces the existing member with the introduced one, or overrides it when a base type defines it. The two members must be compatible: for example, PostSharp reports LA0072 when their visibility differs, and an error when the member of the base type is sealed or not virtual.
  • OverrideOrIgnore also overrides the existing member, but skips the introduction instead of failing when the member of the base type cannot be overridden.

Otherwise, rename the existing member or the introduced one.

In the following example, the introduction is skipped in Customer, which keeps its own Describe method, and happens in Supplier.

using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;

namespace Errors.LA0060_Fixed;

[PSerializable]
public class DescribableAttribute : InstanceLevelAspect
{
    // The introduction is skipped when the target class already defines the method.
    [IntroduceMember( OverrideAction = MemberOverrideAction.Ignore )]
    public string Describe() => $"Instance of {this.Instance!.GetType().Name}";
}

[Describable]
public class Customer
{
    public string Name { get; set; } = "Alice";

    public string Describe() => $"Customer {this.Name}";
}

[Describable]
public class Supplier
{
}

public static class Program
{
    public static void Main()
    {
        Console.WriteLine( new Customer().Describe() );

        // The method introduced into Supplier is not visible at compile time, so it is called with the dynamic keyword.
        dynamic supplier = new Supplier();
        Console.WriteLine( supplier.Describe() );
    }
}
Customer Alice
Instance of Supplier

See Also

Reference

IntroduceMemberAttribute
MemberOverrideAction

Other Resources

Introducing Interfaces, Methods, Properties and Events into Existing Classes