How Do I Specify the Interfaces an Argument must Implement?

T.C.

Member
Joined
Oct 8, 2010
Messages
12
Programming Experience
Beginner
I have an interface called IBaselineControl. Now I'm trying to write a procedure which requires, as an argument, a Control which implements the IBaselineControl interface. However, I don't know the syntax for this.

VB.Net allows us to require multiple interface implementations along with class inheritance when writing constraints for generic types. The syntax used there suggests that something like this might work:
Public Sub Test(X As {Control, IBaselineControl})​

Unfortunately, that syntax doesn't work and I'm unable to find any syntax which does. Can anyone provide advice?

-TC
 
To constrain T to types that implement ISomeInterface:

VB.NET:
    Private Sub DoSomething(Of T As ISomeInterface)(ByVal blah As T)

    End Sub

Multiple interfaces:

VB.NET:
    Private Sub DoSomethingElse(Of T As {ISomeInterface, ISomeOtherInterface})(ByVal blah As T)

    End Sub
 
T.C. said:
write a procedure which requires, as an argument, a Control which implements the IBaselineControl interface
I'd say this simply requires you to specify IBaselineControl as type, unless you require the argument to be a type Control and also type IBaselineControl.
VB.NET:
Sub Method(arg As IBaselineControl)
Generics, as you mentioned, and MattP responded to, allow you to have strongly typed arguments and return values by user specified type(s), where as replied you can define type constraints. Generics is specified using the Of keyword, here is an introduction: Generic Types in Visual Basic (Visual Basic)
 
MattP's solution worked. I've modified my code to use his technique, and I now have much cleaner code, with many fewer CType statements. Thank you.

My problem was finding a way to constrain an argument type; with MattP's help, I was able to solve that problem by using a generic procedure; however, it strikes me that generic procedures do not offer a general solution to the problem of constraining argument types. This is because generic procedures require that I specify a concrete type every time I call the procedure, and that isn't always possible or desirable. For instance, it isn't possible when defining event procedures, and it isn't desirable in situations like this:

VB.NET:
Public Sub DoSomething(Of T As {ISomeInterface, ISomeOtherInterface})(ByVal ParamArray Blah() As T)

That declaration not only constrains all members of Blah() to implement ISomeInterface and ISomeOtherInterface, but also constrains them to use the same implementation of those interfaces, which isn't necessarily desirable.

My conclusion is that VB.Net, although a great language, isn't as flexible as it could be in this regard.


-TC


(JohnH: Yes, my procedure requires the argument to be a Control and also an IBaselineControl. If it hadn't, you're right, I would have been overlooking a much simpler solution. Thanks.)
 
You could define a base type (MustInherit/MustOverrides if you will) that inherits Control and implements ISomeInterface, and use that as parameter type. That would though move the arguments required type from the generic Control+ISomeInterface (independently) to your specific base type (that is a Control+ISomeInterface).
 
MattP's solution worked. I've modified my code to use his technique, and I now have much cleaner code, with many fewer CType statements. Thank you.

My problem was finding a way to constrain an argument type; with MattP's help, I was able to solve that problem by using a generic procedure; however, it strikes me that generic procedures do not offer a general solution to the problem of constraining argument types. This is because generic procedures require that I specify a concrete type every time I call the procedure, and that isn't always possible or desirable. For instance, it isn't possible when defining event procedures, and it isn't desirable in situations like this:

VB.NET:
Public Sub DoSomething(Of T As {ISomeInterface, ISomeOtherInterface})(ByVal ParamArray Blah() As T)

That declaration not only constrains all members of Blah() to implement ISomeInterface and ISomeOtherInterface, but also constrains them to use the same implementation of those interfaces, which isn't necessarily desirable.

My conclusion is that VB.Net, although a great language, isn't as flexible as it could be in this regard.


-TC


(JohnH: Yes, my procedure requires the argument to be a Control and also an IBaselineControl. If it hadn't, you're right, I would have been overlooking a much simpler solution. Thanks.)

It seems to me that you're expecting a bit much. Your declaration uses a ParamArray and so, like any ParamArray and, in fact, any array, every element must be, inherit or implement the type you declare the array as. You have declared your array as type T so every element must be type T. You're expecting to be able to pass an indeterminate number of arguments to the method and also specify multiple independent type constraints on those arguments. I'm not sure that you'd get that anywhere.

If you know exactly how many arguments you intend to pass then you don't need to use a ParamArray. You can simply declare that many parameters each with a different generic type, e.g.
VB.NET:
Public Sub DoSomething(Of T1 As {ISomeInterface, ISomeOtherInterface}, T2 As {ISomeInterface, ISomeOtherInterface})(ByVal p1 As T1, ByVal p2 As T2)
Now you can pass two objects of any two types, as long as both implement those interfaces.

Beyond that, you'd just have to throw an exception in the method if an argument was an invalid type. That's how the DataSource property of some controls works with regards to IList and IListSource.
 
This is because generic procedures require that I specify a concrete type every time I call the procedure, and that isn't always possible or desirable. For instance, it isn't possible when defining event procedures,
When dealing with events it is better to think in terms of the class that defines them, in this case you'd be defining a generic class where one of its type parameters define the generic event. When the type parameter is supplied to class constructor the generic members are compiled to the specific given type, so you won't see (Of type) in event handlers. One basic example:
VB.NET:
Public Class Sample(Of evT As EventArgs)
    Public Event Happened As EventHandler(Of evT)
End Class
then you may have a WithEvents something As New Sample(Of MouseEventArgs) object and the event handler becomes:
VB.NET:
Private Sub something_Happened(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles something.Happened
Also, type parameters for generic methods usually isn't actually specified by client code, when Option Infer is turned on (default) these are automatically inferred by compiler from the supplied argument.
and it isn't desirable in situations like this:
Code:

Public Sub DoSomething(Of T As {ISomeInterface, ISomeOtherInterface})(ByVal ParamArray Blah() As T)

That declaration not only constrains all members of Blah() to implement ISomeInterface and ISomeOtherInterface, but also constrains them to use the same implementation of those interfaces, which isn't necessarily desirable.
As jmcilhinney indicated the type constraint is simply T, which is not different from any other As type definition you give elsewhere. Again, if you think in terms of a generic class definition then this is where type is specified and the method definition would be down to just "arg As T".
"same implementation"? I think you mean same combined definition again, implementation is the actual members that implement the interface members.

When you're talking about a method parameter constraint to two interfaces you should consider if the method serves two different purposes and should perhaps be split to two methods. It is more common for a generic class to have combined needs for various usage throughout the class than a single generic method.
 
Back
Top