I am trying to implement record types to make comparing less complex. But I ran into issues comparing records to each other. I expect records to be equal when properties are equal to each other but this isn't the case in my code..
I have a record class called MyAlarm
with some properties. It inherits from the interface IAlarm
which is empty.
public record MyAlarm : IAlarm
{
public int Prop1 { get; init; }
public int Prop2 { get; init; }
}
A class called VisibleAlarm
has the IAlarm as property plus some extra data.
public record VisibleAlarm
{
public IAlarm InternalAlarm { get; init; }
public string Message { get; set; }
}
In a class called AlarmService
the VisibleAlarms are listed and updated when needed. This service has a List of visible alarms.
Further in this alarm service the list is checked if an alarm already exists depending on the IAlarm property. I have tried two methods:
public class AlarmService
{
private List<VisibleAlarm> _alarms = new();
// ... Other code that handles alarm stuff
private VisibleAlarm GetExistingAlarm1(IAlarm alarm)
{
return _alarms.FirstOrDefault(a => a.InternalAlarm == alarm);
}
private VisibleAlarm GetExistingAlarm2(IAlarm alarm)
{
foreach (var existingAlarm in _alarms)
{
if (existingAlarm.InternalAlarm == alarm)
{
return existingAlarm;
}
}
}
}
When debugging the code I see that the record properties of the existingAlarm.InternalAlarm and the given alarm match but still the GetExistingAlarm
methods return both false. Am i missing something or must I implement a IEqualityComparer because of interface IAlarm?
Cheers
CodePudding user response:
In your line of code:
return _alarms.FirstOrDefault(a => a.InternalAlarm == alarm);
the a.InternalAlarm == alarm
is calling operator==
rather than object.Equals()
to do the comparison.
You can fix this by changing the code to:
return _alarms.FirstOrDefault(a => a.InternalAlarm.Equals(alarm));
The following program demonstrates the difference:
using System;
static class Program
{
public static void Main()
{
MyAlarm ma1 = new MyAlarm { Prop1 = 1, Prop2 = 2 };
MyAlarm ma2 = new MyAlarm { Prop1 = 1, Prop2 = 2 };
VisibleAlarm va1 = new VisibleAlarm { InternalAlarm = ma1, Message = "message" };
VisibleAlarm va2 = new VisibleAlarm { InternalAlarm = ma2, Message = "message" };
Console.WriteLine(ma1 == ma2); // True
Console.WriteLine(va1 == va2); // True
Console.WriteLine(va1.InternalAlarm == va2.InternalAlarm); // False
Console.WriteLine(va1.InternalAlarm.Equals(va2.InternalAlarm)); // True
}
public interface IAlarm
{
int Prop1 { get; }
int Prop2 { get; }
}
public record MyAlarm : IAlarm
{
public int Prop1 { get; init; }
public int Prop2 { get; init; }
}
public record VisibleAlarm
{
public IAlarm InternalAlarm { get; init; }
public string Message { get; set; }
}
}
Output:
True
True
False
True
The reason this isn't working for you is because InternalAlarm
is of type IAlarm
and not MyAlarm
. If you change the type to MyAlarm
, you'll get the comparison as true
rather than false
.
This is because IAlarm
does not define an operator==
(note: such an operator would be static).