Test for generic interface


K

kasper.rung

I have a problem formulating a test to see if an object is implementing
a generic interface.

I have the following:

public interface IGeneric<T>
{
void Foo();
}

public class StringClass : IGeneric<string>
{
public void Foo()
{/** something**/}
}

If i happen to get a hold of an object (which could be a StringClass),
how do i check if it implements the IGeneric<> interface, and if it
does, how do i get a hold of the fact that the generic parameter is a
string?

Thank you,
Krung
 
Ad

Advertisements

M

Marc Gravell

Well, each usage creates a separate interface, and note that a class could
happily implement IGeneric<string> and IGeneric<int> and IGeneric<float>.

You can look at reflection (see below); however, note that (with a few
exceptions) in most circumstances you really want to check if it implements
a *specific* one (even if that is using a TSomething from another generic),
in which case you can just check if it is IGeneric<TSomething>.

Did you have a specific purpose in mind? This could yield a better answer...

Marc

using System;
class Program {
static void Main()
{
Demo obj = new Demo();
Type genericIDemoType = typeof(IDemo<>);
foreach (Type interfaceType in obj.GetType().GetInterfaces())
{
if (interfaceType.IsGenericType)
{
Type test = interfaceType.GetGenericTypeDefinition();
if (test == genericIDemoType)
{
Console.WriteLine("Supports IDemo<> with type: " +
interfaceType.GetGenericArguments()[0].Name);
}
}
}
}
}
interface IDemo<T>
{
void SomeMethod(T param);
}
class Demo : IDemo<string>, IDemo<int>
{
public void SomeMethod(string param)
{}
public void SomeMethod(int param)
{}
}
 
K

kasper.rung

Hi Marc,

Thank you for the reply.

I am aware that a class could implement the interface more than once,
and in fact i am using this already.

The scenario is of course bigger than my one-class example.

I find it very usefull that i can "tag" a class with two pieces of
information with a generic interface at the same time very useful. I
can tag it with both the interface and the generic argument. I can put
this in a very readable and compact line.

I have considered using attributes for this tagging, but they do no
give me the ability to place a contract on the classes, as an interface
does. That is why i am sticking to interfaces so far.

My scenario is this:

At some point i create a user control. If this user control is
implementing a certain generic interface (IListener<T> or similar), it
means that this user control wants to be notified, when there are
updates to a certain part of datastore.

Let us say we have a user control implementing a IListener<Rates>, this
user control should after being created, be signed up by someone else
to the list of those who are interested in updates of the Rates.

The problem is that i cannot test any user control directly to see if
it implements the IListener<Rates>, as i have several hundred other
things to listen for. Besides Rates, we have Units, Customers,... and
the list goes on. I cannot loop to see if the usercontrol by chance
implements IListener<Maybe_this_BusinessObject>, as it would simply
take too long.

My IListen<T> has a base (IListenBase), but that is just to speed up
the detection. It does not solve anything.

What i really need is a way to ask a more general question such as:

If( userControl is IListen<> )

But i can only get away with writing the IListen<> inside a typeof()
call.

I managed to get the Rates type out of a IListen<Rates>, but that is
only the second half.

Thanks,
Krung
 
M

Marc Gravell

How about:

interface IListenBase
{} // leave empty so no implementation required
interface IListen<T> : IListenBase
{
// actual members
}

Now you can check (the easy way) to see if something implements IListenBase,
and then (if they do), look at reflection to see which IListen<> interfaces
they support (as per my example).

Marc
 
K

kasper.rung

Hi Marc,

Thank you again for replying.

I am sorry for changing the name of the interface by mistake, but let's
continue with the IListen<>.

As far as I can see, your suggestion is exactly what I have tried to
communicate with the

"My IListen<T> has a base (IListenBase), but that is just to speed up
the detection. It does not solve anything. "

part of the previous post.

I have an empty IListenBase as a base for the generic interface. Bu
that does not change anything. This is because of two things:

A) knowing that a class implements the IListenBase, does not tell me
what kind of IListen<> it implements. It does not get me any closer to
the solution. As i wrote it speeds up the detection, as i can write
"if(component is IListenBase)" and know if i am getting close, but it
does not tell me anything more.

B) There is no guard against some looney programmer might implement the
IListenBase, but not any actual IListen<> interface.

What I really need is some finer grained distinction in the C#
language/.Net platform, that can says:

"Yes, this object implements IListen<>' and "The argument to IListen<>
is Rates".

I realize that IListen<Customer> and IListen<Rates> are two different
interfaces. But i am baffled by the fact that there seems to be no
simple way to test for the fact that there is a common denominator in
the IListen<> generic interface.

If i say "Find all references" in Visual Studio 2005 on the name of the
generic interface, it finds all my implementations of IListen<>, no
matter what i have given as the generic argument.

I of course know that VS 2005 and the .Net platform is not the same,
but i am refering to the idea. Visual Studio is aware of the connection
between IListen<>, IListen<Rates> and IListen<Customers>, where as the
C# language doesn't have any way of expressing that.

I am experimenting with the reflection part, looping through all the 32
interfaces my user controls are implementing, checking by string
comparison if any of the interfaces might contain some magic strings,
but that is slow and very inelegant.

Sigh.

Thank you for taking the time to answer,
Kasper
 
M

Marc Gravell

OK - one thing at a time.

Re the IListen [I'll drop the Base for brevity] / IListen<T>, I was
suggesting using IListen as a marker only. If something implements
IListen<T> for some T then it *must* implement IListen, so you can use "does
it implement IListen" as a quick first stab. Then only *if* it implements
IListen do you look at reflection, under the assumption that it could have
0, 1 or many IListen<T> implementations.

Re checking with strings... don't do that. I posted demo code in my first
example that identified the exact generic types of IListen<T> without
reverting to anything that ugly. If necessary, you can also use
MakeGenericMethod to then switch (via reflection) to proper typed (generic)
code - for instance you could have a method as below; you can get the
generic method via reflection, and call MakeGenericMethod using the Type
found previously to make and invoke the *real* code. Then when you Invoke()
it, it will (after passing the objects) be running in nicely compiled code
again.

void HookListener<T>(IListen<T> source) where T : new() {
// do some interesting things involving T and source
}

Marc
 
Ad

Advertisements

K

kasper.rung

I think I see things more clearly now. The things I was experimenting
with is going in the same direction as your first example. I will stick
to your example and loose the string comparison.

Regarding the first quick stab, I think we are talking about the same
thing. At this point I don't think I will implement such an
optimization just yet, but it is an obvious optimization. I think there
might be a risk of someone implementing the non-generic interface,
without the generic one. I like defensive programming.

The "Sigh" in my previous post was about the fact that we need to
resort to reflection. I would have liked to see a
language-kind-of-contruct do it for me. After all we got a nice "is"
operator. It would be more elegant if it could handle a generic
interface without a type argument. Wether or not it would end up in
reflection behind the curtains anyway, is less important. I am sure the
..Net guys' implementation is faster than mine anyway.

THank you for your help.
- Kasper
 
M

Marc Gravell

One other thought... it occurred to me that of course you don't need to use
MakeGenericMethod at all... once you have the Type of the interface, that
you know is a closed form of IListen<>, then you can just obtain and invoke
the MethodInfo via reflection, which will *be* the generic method.

But yes... generics are only directly useful in their intended form when the
system can figure out the closed type.

Marc
 
Ad

Advertisements

K

kasper.rung

I like the way of thinking of the interface as an open or closed form.
That makes sense to me.

I think line 9-12 in your first example nails the question i had. First
a check to see if it is generic, and the a check to see of it has the
same "definition". I was lacking a way to formulate a comparison of the
"definition". Too bad we have to loop and all, but it is acceptable.

Thank you,
Kasper
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top