简体   繁体   中英

In C# how to get different IEqualityComparer<T> instance if generic type implements an interface

I have a generic method with unconstrained generic type. I need to get a different IEqualityComparer if type T implements an interface.

A code looks roughly like this:

public SomeState MergeCollection<T>(
    ICollection<T> thisValue, 
    ICollection<T> otherValue, 
    SomeStrategy strategy = SomeStrategy.Default, 
    IEqualityComparer<T> comparer = null)
{
    comparer = comparer ?? GetComparer<T>(strategy);
    // code using comparer
}

public IEqualityComparer<T> GetComparer<T>(SomeStrategy strategy)
{
    if(typeof(IMerge).IsAssignableFrom(typeof(T)))
    {
        return GetMergeComparer<T>(strategy);
    }
    else
    {
        return EqualityComparer<T>.Default;
    }
}

Seems like a typical case for template specialisation yet C# does not support such feature as far as I know. I was also thinking about static class implementing a strategy pattern to swap the function for grabbing the comparer yet static will be implemented for all types so type-method dictionary lookup is necessary. Generating IL code for this seems to be a last resort and not worth the effort considering the code is not that heavily used.

What is the best way to change the behaviour of a method in question so it will get a special case if T implements IMerge? I ask because theoretically it should be possible to define behaviour at compile time or at least at initialisation time (static constructor) if it won't change during runtime.

  1. I don't think there is anything wrong with your existing code. Personally I'd keep it as is.

    IMO optimizing this before you have evidence that it's performance critical is premature optimization.

  2. If you really want to cache the result of the comparison, you could use something like:

     static class MergeComparerHelper<T> { static bool SupportsMerge = typeof(IMerge).IsAssignableFrom(typeof(T)); } 

    This uses the fact that each generic instantiation gets its own static fields. You can use a private nested class for this.

    Note however that this still incurs the cost of a runtime dispatch, since the current implementation of the .NET JITter does not produce specialized implementations for different reference-type T s.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM