VB.NET Generic constraints and subclasses
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 efficie开发者_StackOverflow中文版nt way to do this?
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.
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.
精彩评论