Welcome to CrankyGoblin.Com Sign in | Join | Help

Public Class GeoffAppleby

Inherits Microsoft.VisualBasic.MVP : Implements IBrainFart
Douglas Stockwell's Generics Quiz

Douglas Stockwell posed an interesting problem the other day. He wanted to know if there was a way to make a piece of code work without falling down to reflection.

Personally, I can't see any way to do it without reflection, so I thought I'd post my answers on how to do it with reflection here :)

The problem is like this.

You have to interfaces defined:

Public Interface IA

 

End Interface

 

Public Interface IB

 

End Interface

And you have a generic method that demands a generic type T such that T implements both IA and IB. There's also a situation that takes parameter of type IA.

Public Class SomeClass

    Sub AandB(Of T As {IA, IB})(ByVal anb As T)

        MsgBox("here i am")

    End Sub

 

    Sub Situation(ByVal a As IA)

        If TypeOf a Is IB Then

            'call AandB() here somehow.

        End If

    End Sub

End Class

So the question was: How do you call AandB() passing in the parameter 'a' from Situation()?

At first glance it's easy, but it's actually not. I put the code into visual studio thinking it would be a cinch, but then moment I actually tried to call AandB() it all broke :)

Using reflection however it's quite simple.

Public Class SomeClass

 

    Sub AandB(Of T As {IA, IB})(ByVal anb As T)

        MsgBox("here i am")

    End Sub

 

    Sub Situation(ByVal a As IA)

        If TypeOf a Is IB Then

            Dim paramType As System.Type = CObj(a).GetType()

            Dim classType As System.Type = GetType(SomeClass)

            Dim method As System.Reflection.MethodInfo = classType.GetMethod("AandB", _

                Reflection.BindingFlags.Public _

                Or Reflection.BindingFlags.Instance _

                Or Reflection.BindingFlags.DeclaredOnly)

            Dim genericMethod As System.Reflection.MethodInfo = method.MakeGenericMethod(paramType)

            genericMethod.Invoke(Me, New Object() {a})

        End If

    End Sub

End Class

There's obviously no error checking going on (which you really should have) but it works.

Posted: Friday, 6 October 2006 9:46 AM by Geoff Appleby
Filed under: ,

Comments

Darren Neimke said:

Geoff, why wouldn't you create such a class like so:

public class SomeClass<T> where T : IA, IB {

   public void AandB(T anb) {

       Console.WriteLine( "here i am" ) ;

   }

   public void Situation(IA a) {

       if (a.GetType() == typeof(T)) {

           T tmp = (T)a;

           AandB(tmp);

       }

   }

}

public interface IA { string A { get; set; } }

public interface IB { string B { get; set; } }

# October 5, 2006 9:26 PM

Geoff Appleby said:

Ah, I'm glad you asked :)

The simple answer is 'because'.

The challenge here is not 'how can i change this code to make it work' but only 'how can i make it work'.

The difference is subtle - you can only insert code between the

If TypeOf a Is IB Then

and

End If

lines (or c# equivalents).

What you've done is demanded that the caller MUST have some type which implements both IA and IB - they can't instantiate and call methods on SomeClass without it. But the code I showed above does not DEMAND that the caller have a class that implements both IA and IB, it just takes advantage of the cases where they HAPPEN TO have a class that does.

To be honest, if I were to write this sort of situation in my own code, I would decide that it's time to change my API in some way so that I could remove the need for the reflection code.

Public Interface IC

   Inherits IA

   Inherits IB

End Interface

Sub Situation(ByVal a As IA)

   If TypeOf a Is IC Then

       Situation(CType(a, IC))

   End If

End Sub

Sub Situation(ByVal a As IC)

   AandB(Of IC)(a)

End Sub

And then pushed some of the functionality back on the caller that if they want method AandB() to be called, they need an IC.

But it really does depend on the situation (no pun intended). I'd try and make it easier, but when you have a third party API that works this way, there's not much you can do except work with what you've got available.

# October 5, 2006 10:12 PM

Darren Neimke said:

Gotcha.  Sorry, I hadn't followed the link to the original article until after I posted my solution.

# October 6, 2006 1:06 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

To submit your comment, click on these pictures:
  • Geoff's big sister's tongue
  • Sleepy Geoff
  • Searching Geoff
Gaptcha Image - No Peeking! Gaptcha Image - No Peeking! Gaptcha Image - No Peeking!
Gaptcha Image - No Peeking! Gaptcha Image - No Peeking! Gaptcha Image - No Peeking!
Gaptcha Image - No Peeking! Gaptcha Image - No Peeking! Gaptcha Image - No Peeking!
Can't recognise the people in these pictures? Look here for a quick introduction.
There's a time limit for you to get your comment submitted before this set of pictures expires. If you think it's been longer than 10 minutes, get some new pictures first (you won't lose what you've typed so far).
Get some new pictures 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS