| Severity | Error |
| Reported by | PostSharp |
| Message | Cannot introduce event "<Event>" into type "<TargetType>" because an event with the same name, but of a different type, is defined in type "<DeclaringType>". |
Cause
When an aspect introduces an event with IntroduceMemberAttribute and sets its OverrideAction to OverrideOrFail, PostSharp replaces or overrides the event of the same name that the target type already defines. When the delegate type of this event differs from the type of the introduced event, the introduced event cannot replace it, and PostSharp reports LA0064.
<DeclaringType> is the type that defines the existing event: the target type itself, or one of its base types.
In the following example, the [NotifyChanged] aspect introduces a Changed event of type EventHandler into Customer, which already defines a Changed event of type EventHandler<string>.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0064_Error;
[PSerializable]
public class NotifyChangedAttribute : InstanceLevelAspect
{
[IntroduceMember( OverrideAction = MemberOverrideAction.OverrideOrFail )]
public event EventHandler? Changed;
protected void OnChanged() => this.Changed?.Invoke( this.Instance, EventArgs.Empty );
}
[NotifyChanged]
public class Customer
{
public string Name { get; private set; } = "Alice";
// The aspect introduces an event with the same name, but of type EventHandler.
public event EventHandler<string>? Changed;
public void Rename( string name )
{
this.Name = name;
this.Changed?.Invoke( this, name );
}
}
[NotifyChanged]
public class Supplier
{
}
public static class Program
{
public static void Main()
{
Console.WriteLine( $"Customer.Changed: {typeof(Customer).GetEvent( "Changed" )?.EventHandlerType?.Name}" );
Console.WriteLine( $"Supplier.Changed: {typeof(Supplier).GetEvent( "Changed" )?.EventHandlerType?.Name}" );
}
}
error LA0064: LA0064_Error.cs(23,40): Cannot introduce event "Changed" into type "Errors.LA0064_Error.Customer" because an event with the same name, but of a different type, is defined in type "Errors.LA0064_Error.Customer".
Resolution
- Give the introduced event and the existing event the same delegate type.
- Set the OverrideAction of the introduction to OverrideOrIgnore: PostSharp then skips the introduction when the existing event has another type, and still overrides an event of the same type. Ignore skips the introduction whenever the event exists.
- Otherwise, rename the existing event or the introduced one.
In the following example, the introduction is skipped in Customer, which keeps its EventHandler<string> event, and happens in Supplier.
using System;
using PostSharp.Aspects;
using PostSharp.Aspects.Advices;
using PostSharp.Serialization;
namespace Errors.LA0064_Fixed;
[PSerializable]
public class NotifyChangedAttribute : InstanceLevelAspect
{
// The introduction is skipped in a class that defines the event with another type.
[IntroduceMember( OverrideAction = MemberOverrideAction.OverrideOrIgnore )]
public event EventHandler? Changed;
protected void OnChanged() => this.Changed?.Invoke( this.Instance, EventArgs.Empty );
}
[NotifyChanged]
public class Customer
{
public string Name { get; private set; } = "Alice";
public event EventHandler<string>? Changed;
public void Rename( string name )
{
this.Name = name;
this.Changed?.Invoke( this, name );
}
}
[NotifyChanged]
public class Supplier
{
}
public static class Program
{
public static void Main()
{
Console.WriteLine( $"Customer.Changed: {typeof(Customer).GetEvent( "Changed" )?.EventHandlerType?.Name}" );
Console.WriteLine( $"Supplier.Changed: {typeof(Supplier).GetEvent( "Changed" )?.EventHandlerType?.Name}" );
}
}
Customer.Changed: EventHandler`1
Supplier.Changed: EventHandler
See Also
Reference
IntroduceMemberAttribute
MemberOverrideAction
Other Resources
Introducing Interfaces, Methods, Properties and Events into Existing Classes