views:

38

answers:

2

Consider the following extension method:

    <Extension()> _
    Public Function Satisfies(Of T)(ByVal subject As T, ByVal specification As ISpecification(Of T)) As Boolean
        Return specification.IsSatisfiedBy(subject)
    End Function

This works as expected if subject is the exact class being operated on by the specification. However, if the specification is examining the super-class of T, this extension will not work unless subject is explicitly cast to the super-class. Is there a way I can avoid this? So far, the best I've been able to come up with is:

    <Extension()> _
    Public Function Satisfies(Of T As Class, K As Class)(ByVal subject As T, ByVal specification As ISpecification(Of K)) As Boolean
        Return specification.IsSatisfiedBy(TryCast(subject, K))
    End Function

But I can't help but think there's a better way....

Update:

Since I (apparently) can't get this to work exactly as I'd like in VB.NET due to limitations in the language itself, is my second attempt the safest/most efficient way to do this?

+1  A: 

I was thinking something like this should work, but it doesn't:

<Extension()> 
Public Function Satisfies(Of TBase, TDerived As TBase)(
           ByVal subject As TDerived, 
           ByVal specification As ISpecification(Of TBase)) As Boolean
    Return specification.IsSatisfiedBy(subject)
End Function

The VB compiler says: 'Extension method 'Satisfies' has type constraints that can never be satisfied', which is rather strange, because in C# it does work:

public static class Extensions
{
    public static bool Satisfies<TDerived, TBase>(
              this TDerived subject, 
              ISpecification<TBase> spec) where TDerived:TBase
    {
        return spec.IsSatisfiedBy(subject);
    }
}

public interface ISpecification<T>
{
    bool IsSatisfiedBy(T subject);
}

So the answer seems to be: use C# for this construct, or, as @Dario noted, implement the Satisfies method as a regular Module method instead of an extension method.

jeroenh
That's really strange, yes. Most importantly because without the `<Extension()>`, it works.
Dario
I tried this exact same thing..and unfortunately, switching to C# isn't really an option..I can't believe there isn't a way to do this in VB.NET....
DanP
@DanP I would simply put the ISpecification interface together with the extension method in a separate (C#) project. You don't have to switch your whole project, but at least this scenario would work... In the end it's all about 'getting things done', right?
jeroenh
@Dario good point about removing the <Extension()> attribute, didn't think of that; edited it in.
jeroenh
@Dario: True, but the whole point of this was to get some nice syntactic sugar; thus the need for the extension method.
DanP
+3  A: 

This is by the design of the Extension methods as they are applied in VB. I'm not sure why they built extensions in differently for VB, but for VB the constraint TDerived:TBase can't exist. Unfortunately, without it you can't cast TDerived to a TBase so the IsSatisfiedBy function fails. For reference:

Extension method '<methodname>' has type constraints that can never be satisfied

Your first implementation appears to be the only one that will work, and this is a limitation of how the Extension methods are designed in the VB framework.

Joel Etherton
@Joel: Thanks for the confirmation, have updated my question in an attempt to get a reasonable work-around for this limitation.
DanP