| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot introduce the interface <Interface> into the type <TargetType> because this type already implements it. To keep the existing implementation, set OverrideAction to Ignore. |
Cause
An aspect introduces an interface into its target type with IntroduceInterfaceAttribute, with an IntroduceInterfaceAdviceInstance returned by an advice provider, or as a CompositionAspect. When the target type already implements this interface, directly or through a base type, PostSharp follows the OverrideAction of the introduction. Its default value, Fail, reports LA0004 on the target type instead of replacing the existing implementation.
In the following example, the [Describable] aspect introduces IDescribable into Customer, which already implements it.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0004_Error;
public interface IDescribable
{
string Describe();
}
[PSerializable]
[IntroduceInterface( typeof(IDescribable) )]
public class DescribableAttribute : InstanceLevelAspect, IDescribable
{
public string Describe() => $"Instance of {this.Instance!.GetType().Name}";
}
// The aspect introduces IDescribable into a class that already implements it.
[Describable]
public class Customer : IDescribable
{
public string Name { get; set; } = "Alice";
public string Describe() => $"Customer {this.Name}";
}
public static class Program
{
public static void Main()
{
Console.WriteLine( new Customer().Describe() );
}
}
error LA0004: LA0004_Error.cs(22,14): Cannot introduce the interface Errors.LA0004_Error.IDescribable into the type Errors.LA0004_Error.Customer because this type already implements it. To keep the existing implementation, set OverrideAction to Ignore.
Resolution
- Set the OverrideAction property of the introduction to Ignore: the target type keeps its own implementation, and the aspect introduces the interface only into the types that do not implement it. A CompositionAspect sets its OverrideAction property in its constructor.
- Otherwise, remove the interface from the target type, or do not apply the aspect to this type.
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.LA0004_Fixed;
public interface IDescribable
{
string Describe();
}
[PSerializable]
// The introduction is skipped when the target class already implements the interface.
[IntroduceInterface( typeof(IDescribable), OverrideAction = InterfaceOverrideAction.Ignore )]
public class DescribableAttribute : InstanceLevelAspect, IDescribable
{
public string Describe() => $"Instance of {this.Instance!.GetType().Name}";
}
[Describable]
public class Customer : IDescribable
{
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 interface introduced into Supplier is not visible at compile time, so the object is cast at run time.
var supplier = (IDescribable) (object) new Supplier();
Console.WriteLine( supplier.Describe() );
}
}
Customer Alice
Instance of Supplier
See Also
Reference
IntroduceInterfaceAttribute
InterfaceOverrideAction
CompositionAspect
Other Resources