Home > front end >  How to check if a list contains special class in C#
How to check if a list contains special class in C#

Time:01-28

I have several classes which inherit from abstract class "Illness" and overrides a field "name",
Illness.cs:

namespace health;
abstract class Illness{
    public abstract string name { get;}
    public string something = "sometihng";
}

Cancer.cs:

namespace health;
class Cancer : Illness{
    public override string name { 
        get{ return"Cancer";}
    }
}

Covid.cs:

namespace health;
class Covid : Illness{
    public override string name { 
        get{ return"Covid-19";}
    }
}

In Main class, I have List<Illness> illnesses which is empty and I want to make a method which adds a value to "illnesses" list only if this list doesn't contain the given class already, I tried to do this:

public void addIllness(Illness illness){
        if (!illnesses.Contains(illness)){
            illnesses.Add(illness);
        }
    }

but this doesn't work much because of polymorphism, it compares an abstract class "Illness" to existing values.

CodePudding user response:

Property uniqueness

If you are using Illness.Name to specify something special about the illness, like the type of cancer og covid infection. Then you would like to check name of the illness before adding it to the list of illnesses:

public abstract class Illness
{
    public abstract string Name { get; }
}

public class Cancer : Illness
{
    public Cancer(string cancerName)
    {
        Name = cancerName;
    }

    public override string Name { get; }
}

public class Covid : Illness
{
    public Covid(string covidName)
    {
        Name = covidName;
    }

    public override string Name { get; }
}

public class Main
{
    public Main()
    {
        AddIllness(new Cancer("Breast Cancer"));
        AddIllness(new Cancer("Breast Cancer"));
        AddIllness(new Cancer("Lung Cancer"));
        AddIllness(new Covid("SARS-CoV-1"));
        AddIllness(new Covid("SARS-CoV-2"));
        AddIllness(new Covid("SARS-CoV-2"));
    }

    public List<Illness> Illnesses { get; } = new();

    public void AddIllness(Illness illness)
    {
        if (Illnesses.All(i => i.Name != illness.Name))
        {
            Illnesses.Add(illness);
        }
    }
}

In the above example you'll see that the list of illnesses would only contain 4 items after the Main constructor has been initialized.

Class uniqueness

If you are using the class type as uniqueness criteria you would like to check against all the class types that already exists in the list Illnesses before you would add the Illness

public abstract class Illness
{
    public abstract string Name { get; }
}

public class Cancer : Illness
{
    public override string Name => "Cancer";
}

public class Covid : Illness
{
    public override string Name => "Covid-19";
}

public class Main
{
    public Main()
    {
        AddIllness(new Cancer());
        AddIllness(new Cancer());
        AddIllness(new Covid());
        AddIllness(new Covid());
    }


    public List<Illness> Illnesses { get; } = new();

    public void AddIllness(Illness illness)
    {
        if (Illnesses.All(i => i.GetType() != illness.GetType()))
        {
            Illnesses.Add(illness);
        }
    }
}

In the above example you'll see that the list of illnesses would only contain 2 items after the Main constructor has been initialized.

Overriding EqualityComparer

Another way is to override the Equals and GetHashCode method. Then you would be able to use Contains as in your example.

public abstract class Illness
{
    public abstract string Name { get; }

    public override bool Equals(object obj)
    {
        if (obj == null) return false;
        return GetType() == obj.GetType();
    }

    public override int GetHashCode()
    {
        return GetType().GetHashCode();
    }
}

public class Cancer : Illness
{
    public override string Name => "Cancer";
}

public class Covid : Illness
{
    public override string Name => "Covid-19";
}

public class Main
{
    public Main()
    {
        AddIllness(new Cancer());
        AddIllness(new Cancer());
        AddIllness(new Covid());
        AddIllness(new Covid());
    }


    public List<Illness> Illnesses { get; } = new();

    public void AddIllness(Illness illness)
    {
        if (!Illnesses.Contains(illness))
        {
            Illnesses.Add(illness);
        }
    }
}

In the above example you'll see that the list of illnesses would only contain 2 items after the Main constructor has been initialized.

Even if you are doing it this way, you could also change Illnesses to be a HashSet<Illness> that will automatically check whether the class already exists in the set.

public class Main
{
    public Main()
    {
        Illnesses.Add(new Cancer());
        Illnesses.Add(new Cancer());
        Illnesses.Add(new Covid());
        Illnesses.Add(new Covid());
    }

    public HashSet<Illness> Illnesses { get; } = new();
}

CodePudding user response:

You can (as mentioned by Lei Yang) solve this by checking he type:

  • if(!illnesses.Any(i=>i is typeof(Covid)){ ... } for a specific type.
  • if (!illnesses.Any(i => i.GetType() == illness.GetType())) { ... } comparing the type of the objects.

You could also create a generic method to achieve this in a nice manner:

public void Add<T>(T illness) where T : Illness{
    if(!illnesses.Any(t=>t is T)){
        illnesses.Add(illness);
    }
}

As you are overriding name you could even use that for better performance:

if(!illnesses.Any(i=>i.name == illness.name)){ ... } This is however more or less the explicit version of what (again) @Lei Yang proposed in implementing IEquatable.

This however seems to be a bit strange of an approach, you should use objects when you can have more than one instance of a class, else maybe reconsider adding a "IllnessType" enum beside the Name and ditch the inheritance.

CodePudding user response:

You can check class using GetType method.

if (!illnesses.Any(i => i.GetType() == illness.GetType()))
{
   illnesses.Add(illness);
}
  •  Tags:  
  • Related