Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage this situation by generic programming in C#?

Tags:

c#

generics

I have the code below which implements a logic I need at two places in my code. The code is written in generic way.

It has a defect in it. It does not check whether the given object already exist in the collectionToBeExtended or not. It just add to it, and I will have twice the same item.

I use this code managing two collections, one contains Tags, the other one contains Link entities (POCO). They do not have the same parent object, nor interface. For managing the situation below I don't want to introduce a new common interface for them.

In order to fix the defect above I need put custom logic within the foreach to check whether the given object already member of the collection or not. The Tag and Entity object are different, so there is common ground for comparison. You can see the Tag implementation below.

DRY principle says clearly I should not create the exact implementations, instead I should create some generic solution can deal with both case, or a third and fourth one. My first thought was that, I introduce a switch where I can place custom logic based on object type, but Martin Fowler says in his Refactoring book that switch-cases are smelly areas.

My current knowledge and experience is not enough to solve this issue, so I really appreciate any help!

Generic implementation:

private ICollection<T> AddTo<T> ( IEnumerable<T> toBeAdded , ICollection<T> collectionToBeExtended )
    {

        if ( collectionToBeExtended == null )
        {
            collectionToBeExtended = new List<T> ( );
        }

        if ( toBeAdded != null )
        {
            foreach ( T obj in toBeAdded )
            {
                    collectionToBeExtended.Add(obj);
            }
        }

        return collectionToBeExtended;
    }

Tag implementation:

private ICollection<Tag> AddTo ( IEnumerable<Tag> toBeAdded , ICollection<Tag> collectionToBeExtended )
    {

        if ( collectionToBeExtended == null )
        {
            collectionToBeExtended = new List<Tag> ( );
        }

        if ( toBeAdded != null )
        {
            foreach ( Tag tag in toBeAdded )
            {
                if (!collectionToBeExtended.Any(c => c.Id == tag.Id && c.Name == tag.Name))
                {
                    collectionToBeExtended.Add(tag);
                }
            }
        }

        return collectionToBeExtended;
    }
like image 456
AndrasCsanyi Avatar asked Feb 08 '23 03:02

AndrasCsanyi


2 Answers

All types in C# can equated with x.Equals(y). You can override this equality if you desire.

I would just use IEnumerable<A> to solve this problem. If you want an ICollection<A> afterwards then you can construct a collection from the IEnumerable<A>.

collectionToBeExtended.Concat(toBeAdded).Distinct()
  • Concat
  • Distinct
  • Equals
like image 134
erisco Avatar answered Feb 17 '23 00:02

erisco


I hope this isn't overkill, but extension methods seem to do the trick for me. I hope it helps you too.

public static ICollection<X> AddIf<X>(this ICollection<X> myarray, X val, Func<X, X, bool> check)
    {
        if (myarray.All<X>((c) => check(c, val))) myarray.Add(val);
        return myarray;
    }

This can then be used as

List<string> test = new List<string> { "1", "2", "3", "4", "5" };
test.AddIf<string>("1", (a, b) => !a.Equals(b)); //this will not be added
test.AddIf<string>("6", (a, b) => !a.Equals(b)); //this will be added

Or in your case,

collectionToBeExtended.AddIf((c, tag) => !c.Id.Equals(tag.Id) && !c.Name.Equals(tag.Name))

Make sure to put the extension method in a static class though.

like image 43
Ikechi Michael Avatar answered Feb 17 '23 00:02

Ikechi Michael