0

I have some replicated code and so looking to make a generic method. I have a common named extension method that I'd like to use in the method. Normally, if it wasn't an extension method, I'd create an interface, restrict the generic parameter class by that interface and then you can use that common method. But this doesn't work with extension methods.

Here is my generic method:

public ActionConfirmation<string> CreateUpdateEntity<TExternalEntity, TQuickbooksEntity>(TExternalEntity entity, CompanyPreferencesFinancialsSystemCommon preferences)
    where TExternalEntity : class, OTIS.Domain.IEntity, IFinancials, IExternalMapper<TExternalEntity, TQuickbooksEntity>, new()
    where TQuickbooksEntity : class, Intuit.Ipp.Data.IEntity, new()
{
    return CreateUpdateQuickBooksEntity<TQuickbooksEntity>(
        entity.ToQuickBooksEntity(preferences),
        x => x.Id == entity.FinancialsId,
        entity.FinancialsId);
}

Attempted Interface

public interface IExternalMapper<TExternalEntity, TQuickbooksEntity>
    where TExternalEntity : class, OTIS.Domain.IEntity, new()
    where TQuickbooksEntity : class, Intuit.Ipp.Data.IEntity, new()
{
    static TQuickbooksEntity ToQuickBooksEntity<TExternalEntity>(this TExternalEntity externalEntity, CompanyPreferencesFinancialsSystemCommon preferences);
}

This produces error:

Extension method must be defined in a non-generic static class

And this

public static class VendorExtensions : IExternalMapper<OTIS.Domain.InventoryMgmt.Vendor, Intuit.Ipp.Data.Vendor>
    {
        public static Intuit.Ipp.Data.Vendor ToQuickbooksEntity(this OTIS.Domain.InventoryMgmt.Vendor importedVendor)

Results in Static classes cannot implement interfaces.

I understand why this doesn't work. But don't know how to re-architect the code to support the requirement of using an extension method in a generic method.

crichavin
  • 4,672
  • 10
  • 50
  • 95

3 Answers3

3

They pretty much sum it up with

Extension method must be defined in a non-generic static class

Just define your extension method in a static class

public static class MapperExtensions    
{
     public static TQuickbooksEntity ToQuickBooksEntity<TExternalEntity>(this TExternalEntity externalEntity, CompanyPreferencesFinancialsSystemCommon preferences) 
                        where TExternalEntity : class, OTIS.Domain.IEntity, new()
                        where TQuickbooksEntity : class, Intuit.Ipp.Data.IEntity, new()
     {    
          //return do implimentation    
     }
}

Then when you want to map it get rid of the Interface and use the extension directly.

using namespacetoextensions;

public ActionConfirmation<string> CreateUpdateEntity<TExternalEntity, TQuickbooksEntity>(TExternalEntity entity, CompanyPreferencesFinancialsSystemCommon preferences)
    where TExternalEntity : class, OTIS.Domain.IEntity, IFinancials, new()
    where TQuickbooksEntity : class, Intuit.Ipp.Data.IEntity, new()
{
    return CreateUpdateQuickBooksEntity<TQuickbooksEntity>(
        entity.ToQuickBooksEntity(preferences),
        x => x.Id == entity.FinancialsId,
        entity.FinancialsId);
}

Just to clarify, you are trying to use C# features in a way they simply do not work.

Static classes are sealed and therefore cannot be inherited. They cannot inherit from any class except Object.

Which means your implementation of an interface with your extension method is simple not going to work.

So you have two choices, either remove the interface and use only the extension method directly, like this:

public static class Extensions
{
    public static TExternalEntity ToQuickBooksEntity<TExternalEntity, TQuickbooksEntity>(this TQuickbooksEntity externalEntity)
        where TExternalEntity : class, OTIS.Domain.IEntity, new()
        where TQuickbooksEntity : class, Intuit.Ipp.Data.IEntity, new()
    {
        throw new NotImplementedException();
    }
}

Or you can NOT use an extension method and rather use an interface with an implimentation. (I would show this example, pretty straight forward).

shenku
  • 11,969
  • 12
  • 64
  • 118
  • Thank you for the response. On point one, I do have my extension methods defined in a static class (see VendorExtensions class above). I wasn't setting up my extension method to be generic as each class (Vendor, Customer, etc) will have a very different mapping logic in this extension method .ToQuickbooksEntity(). 2.)How can you use the extension in a generic method without restricting the class by an Interface? When I try this, I get the error TExternalEntity does not have a .ToQuickbooksEntity() method. Sorry if I am missing something obvious. I am just learning about generics. – crichavin Mar 07 '14 at 00:12
  • Your problem is that you are trying to use two features of C# together, when they simply dont. So to solve the problem you have to use one of the approaches rather than both. I'll update my answer above. – shenku Mar 07 '14 at 00:29
  • Thank you! I will scrap the extension then. – crichavin Mar 07 '14 at 01:18
1

If the implementation detail of ToQuickBooksEntity is significantly different for different types of TExternalEntity, then it probably shouldn't be an extension method. It should be an instance method on an appropriate class so that you can take advantage of polymorphism.

If the implementation detail doesn't depend too much on the type of TExternalEntity and you want to keep it as an extension method, then there's no reason to have it defined on an interface. Instead, make it a method on a static class. Any generic type constraints that you need can be generic constraints on the method themselves, you don't need the class to be generic.

Ben Aaronson
  • 6,955
  • 2
  • 23
  • 38
  • Thanks Ben for taking the time to respond. To clarify, I am not making the Extension method generic, but rather a class that needs to use that generic method. I.e. see the VendorExtensions class. It is not generic. But I want to use that .ToQuickbooksEntity() extension method in the CreateUpdateEntity generic method. If I don't have an interface to restrict he TExternalEntity class in this method, the compiler won't know that TExternalEntity has a .ToQuickbooksEntity() ext method. This is where I am stuck. Any thoughts? By the way, thanks for your comment above. – crichavin Mar 07 '14 at 00:17
  • @ChadRichardson I may still be misunderstanding your situation. Why can't you create a static class with no generic parameters, and on it put the extension method ToQuickbooksEntity(), which also takes no generic parameters and has the first argument 'this IEntity externalEntity' and with return type IEntity? Is the reason that you want to use polymorphism to provide multiple possible implementations of ToQuickbooksEntity? – Ben Aaronson Mar 07 '14 at 17:37
0

Extension method must be defined in a non-generic static class

Isn't the error clear? Extension methods should be a static method that should be defined in a non generic static class in order to work. also static classes must inherit from System.Object and cannot implement any interface also.

interface implementation is illegal in static class because static class cannot have instance members, but interfaces won't makes sense without instance members.

Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • Downvote was mine. I removed it as it may have been overly hasty. But it seemed like you were explaining the bit he already understood (as in the last line of the question) – Ben Aaronson Mar 06 '14 at 03:59
  • @BenAaronson I see, I've not noticed that. but what's here to give as work around. nothing. simply he need a static class without any interface that's it. – Sriram Sakthivel Mar 06 '14 at 04:02
  • Yes, the error is clear and as I stated I understand why I get the error. As Ben stated, my question was how to re-architect my code to support this requirement. – crichavin Mar 06 '14 at 23:52