views:

305

answers:

4

Hello,

I have 2 extension methods that convert a MongoDB document to an entity/object.

public static ProductTemplate Convert(this Document document)
{
    return null;
}

public static Product Convert(this Document document)
{
    return null;
}

This gives an expected ambiguous call error so I was wondering how I could fix this?

Friendly greetings,

Pickels

+3  A: 

you could change the names:

public static ProductTemplate ConvertToProductTemplate(this Document document) 
{
    return null;
}

public static Product ConvertToProduct(this Document document)
{
    return null;
}
Sam Holder
Yeah, actually I was just thinking it might be better to just call them ToProductTemplate and ToProduct.
Pickels
This is the .NET way of naming these things. Look up the `Convert` static class.
Blindy
+6  A: 

Functions can't be overloaded by return type. You will have to rename your functions to maybe:

ConvertToProductTemplate() and ConvertToProduct()

or turn them into one function which returns a common base class or interface. (But then the caller will have to do a cast when they get your result)

Dave Markle
Thanks that's the answer I was looking for.
Pickels
or if you really want to keep the name. you could put the extension methods in different namespaces but I suggest sticking with the different names solution since relying on the order of your using statements will result in very hard to read-code
Rune FS
Check out Tomas's answer. It's even better. In my old age, I sometimes forget about using generics.
Dave Markle
@Dave Markle: I'm not sure its better, this is explicit about what types can be converted, the other method could have types which fit the method signature but won't be implemented. With this way if the method exists then you know its been implemented.
Sam Holder
+8  A: 

You could make your Convert method generic:

public static T ConvertTo<T>(this Document doc) where T : SomeBaseClassOrInterface
{
    return null;
}

Then use it like so:

var document = new Document();
var temp = document.ConvertTo<ProductTemplate>(); // returns a ProductTemplate
var prod = document.ConvertTo<Product>(); // returns a Product
Tomas Lycken
+1. Whilst I like this approach it is only appropriate when you have an interface/base class. And if you have many derivitives and only want to convert some of them then you would be able to call the method but would have to check the result for null, or get an exception. I prefer the explicit ConvertToType() style. I'd rather see 3 methods I know I can use than one that works for 3 types but not for 3 others.
Sam Holder
Why to write a generic method for a common interface when you can return that interface from a non-generic method? Please see my answer for more detail.
Piotr Justyna
@bebop: Instead of writing a `ConvertToType()` method for each type you want to be able to convert to, you can just create an empty interface `IConvertibleFromDocument` and apply it to each relevant type. Or just skip the condition on `T`, and throw `InvalidOperationException` if there is no way to convert to the given type.
Tomas Lycken
both of those options seem like hacks. Empty interface seems like a bad idea, there is an fxcop rule for that. Throwing an exception seems like a usability nightmare. Don't see what extra this gives you. with the explicit ConvertToType() you can see what types you can convert to easily. with this you have to ConvertTo and plug in a type which might or might not cause a compile error, or worse a runtime error.
Sam Holder
+1  A: 

I have a feeling that Product and ProductTemplate classes are related somehow (e.g. Product extends ProductTemplate). If I'm right, you can just return the base class (ProductTemplate in this case).

Tomas Lycken suggested to use generic method, which is in my opinion quite good idea, but if there's a common interface for Product and productTemplate, you can just return that interface as well instead of Product and ProductTemplate.

Example (by Tomas Lycken):

public static T ConvertTo<T>(this Document doc) where T : SomeBaseClassOrInterface
{
    return null;
}

Example (by me):

public static SomeBaseClassOrInterface ConvertTo(this Document doc)
{
    return null;
}

And if there's no common interface and you don't want to create a new one, please just change names :)

Piotr Justyna
You are right Product and Template are related. I want the user to be able to design his own products and that info is stored as ProductTemplates. It's a collection of properties each product can have. Still running some tests to see what the best approach is. I thank you for your answer I will certainly look into it.
Pickels
isn't the problem with this that if Product extends Template that you won't know if you have a Product without trying to cast it? If you can always create a Product then you only need the one convert method and if Product does extend Template then you can use the product anywhere you can need a template. I don't see the benefit of returning the base class. enlighten me.
Sam Holder
That's interesting. You've rated Tomas Lycken's answer +1 and now you don't see the benefit of returning a base class. The benefit of returning a base class is just the same as of returning an interface. You can obviously have tons of implementations/extensions of the base class and totally don't care about different converters for each of them. in this case - if you need and explicit implementation of converter - you can just write one.
Piotr Justyna
If you read my comments to Tomas's answer you can see that I'm not so sold on that idea, for the same reasons I'm not sold on this one. The explicit conversions are the best solution if you ask me.
Sam Holder