Cast generic IFoo<T>

A

Alphapage

Hello,

The problem I've come across is that I want to use an interface as an
abstraction. For example, if i have some interface:

public interface IFoo<T>
{
...
}

I can't just refer to it in another class like a non generic interface:
public void process(IFoo foo)
{
...
}

It has to be referred to as something like IFoo<T> to bind it to a specific
T. You can't just refer to a common IFoo method, you have to refer to a
common IFoo method bound to a specific type T, so although your code might
look like its dealing with interfaces in order to actually use this generic
interface pattern you have to keep track of the type argument! This doesn't
seem like much of an abstraction. Ideally an object in random assembly "X"
that knows about interface IFoo should be able to accept an object of type
IFoo in method parameters and be able to call functions defined in the
interface IFoo, but with a generic interface this assembly also needs to know
what the type T is, which seems like a limitation.

Thanks in advance for your help.
 
A

Alun Harford

Alphapage said:
Hello,

The problem I've come across is that I want to use an interface as an
abstraction. For example, if i have some interface:

public interface IFoo<T>
{
...
}

I can't just refer to it in another class like a non generic interface:
public void process(IFoo foo)
{
...
}

It has to be referred to as something like IFoo<T> to bind it to a specific
T. You can't just refer to a common IFoo method, you have to refer to a
common IFoo method bound to a specific type T, so although your code might
look like its dealing with interfaces in order to actually use this generic
interface pattern you have to keep track of the type argument! This doesn't
seem like much of an abstraction. Ideally an object in random assembly "X"
that knows about interface IFoo should be able to accept an object of type
IFoo in method parameters and be able to call functions defined in the
interface IFoo, but with a generic interface this assembly also needs to know
what the type T is, which seems like a limitation.

Well yes, you've defined an IFoo<T> !

As such, code using T will need to understand it (to know which
interface it's actually using).

You can, of cause, create another interface IFoo and make IFoo<T>
implement IFoo

Alun Harford
 
L

Lloyd Dupont

Don't mistake generic type for what you would like them to be!!

IFoo<A> has nothing in common with IFoo<B>!
They are completely different type create dynamically at runtime.

What you ask is a bit akin to ask: "the System.Web.UI and
System.Windows.Controls namespace both contains a Control class, could I use
one in place of the other? common they have the same name!"

If you want to use a method common to both you should do as Alun suggested.
Inherhit IFoo<t> : IFoo.

Surprise, surprise, it's exactly what they did at Microsoft, you'll notice,
for exemple, that
IList<T> : IList
IEnumerator<T> : IEnumerator
ICollection<T> : ICollection
etc....
 
J

Jon Skeet [C# MVP]

Surprise, surprise, it's exactly what they did at Microsoft, you'll notice,
for exemple, that
IList<T> : IList
IEnumerator<T> : IEnumerator
ICollection<T> : ICollection
etc....

That's only true for IEnumerator<T>. IList<T> doesn't extent IList and
ICollection<T> doesn't extend ICollection.

That said, making the generic interface extend a non-generic one is a
fine solution in many cases. It's what I'm doing at the moment with
Protocol Buffers...

Jon
 
J

Jon Skeet [C# MVP]

Noting, IMHO, that doing so assumes the non-generic interface already
exists.

Not necessarily.
I'm not convinced that I'd create a non-generic interface for the
purpose (and as far as I know, Microsoft didn't either), since doing so
pretty much winds up intentionally defeating the point of using the
generic in the first place.

Only for some cases. It depends whether the parts of the API you're
interested in depend on the type parameter. For instance, it would be
handy for my current work if IList<T> implemented a (mythical)
interface called ICountable with a Count property. In my current code
I sometimes need to get the count of an object which I know is an
IList said:
Whatever code's already using the generic interface in its concrete form
must already know the type parameter, so making a generic method to
support the generic interface shouldn't be a problem at all (assuming it's
not suitable for the method itself to be declared using a concrete form of
the generic interface, which I think usually would be the case).

Not necessarily - see my example above. In my case I receive the
object as just "object" and have to cast to *something* - but there's
no appropriate type I can cast to without the type information.

In addition, I need to suppose situations where everything's dynamic -
which means my nongeneric API is actually just as rich in terms of
abilities as my generic API, it just lacks the precise type safety.
That means a lot of explicit interface implementation etc, which isn't
terribly nice but it's the best way available in the situation. I
acknowledge that it's not a terribly common situation though...

(The code is available on github -
http://github.com/jskeet/dotnet-protobufs/tree/master/csharp/ProtocolBuffers
and look at IMessage.cs and IBuilder.cs.)

Jon
 
P

Pavel Minaev

Hello,

The problem I've come across is that I want to use an interface as an
abstraction.  For example, if i have some interface:

public interface IFoo<T>
{
    ...

}

I can't just refer to it in another class like a non generic interface:
public void process(IFoo foo)
{
   ...

}

Why, of course you can:

public void Process<T>(IFoo<T> foo)
{
...
}

Of course, since Process doesn't know what T could possibly be, it
would be rather limited. But, to take some existing interface as an
example, if we were dealing with ICollection<T> here, Process() could
easily access, for example, Count and Clear - other methods would be
more problematic, since you'd need an instance of T to get anything
useful from them.
 
M

Marc Gravell

For info, I've used the same non-generic/generic inherited pair many
times, for example scenarios like property bag implementations. In
reality it isn't a problem; type safety is still enforced by the
underlying type. Typically the generic interface will re-declare ("new")
some (but not all) members with more specific versions.

For example: just because List<T> implements IList, and IList has
Add(object), that doesn't imply that you can *actually* add a string to
a List<int> by cheating through the IList facet.

Marc
 
J

Jon Skeet [C# MVP]

For example: just because List<T> implements IList, and IList has
Add(object), that doesn't imply that you can *actually* add a string to
a List<int> by cheating through the IList facet.

Funnily enough, I hadn't spotted that List<T> implements IList. I
looked at IList<T> but not List<T>.
Hmm. That *might* be very handy...

Jon
 
J

Jon Skeet [C# MVP]

If you know it's an IList<Something>, then you can use it generically and 
have the call chain provide the type.  That's my point.

No, I can't. I know it will be IList<Something> in a non-compiler-
provable way, but I can't determine (at compile-time) which type it
will be. So I can't cast to it.
As convenient?  No, I admit not.  But IMHO it's a better approach and 
should be used unless it's completely impossible for some reason (having a  
hard time envisioning such a scenario, but happy to give the benefit of  
the doubt with respect to ruling something out completely :) ).

When you specify a type, e.g. as a return type or a parameter type,
you can only specify one type. You can't say "It has to take something
which implements both ICountable and IList<T>" - not unless you
introduce another generic type parameter just for that purpose, which
certainly isn't always practical.
If all you know is "object", then it doesn't really matter whether your  
"ICountable" interface is inherited by "IList<T>" or is simply implemented  
as a separate interface.

Yes it does - because I can guarantee (in my situation) that it will
have been created as an IList<T> somewhere. Even if the ICountable
interface existed, however I couldn't necessarily ensure that the
implementation of IList said:
 I don't think it's necessary for the generic  
interface to _inherit_ a non-generic interface for that purpose.

It really, really would have helped in my situation.
But in any case, this isn't comparable to the OP's scenario, which is all 
I was commenting on (thus, my statement in my previous reply that included  
the phrase "for the purpose").

I'm not sure we know enough about the OP's scenario to say for sure.

Jon
 
J

Jon Skeet [C# MVP]

Peter Duniho said:
If you don't know it in a compiler-provable way, then again: I think
that's not comparable to the OP's situation (his code specifically shows
an explicit type declaration).

In the method call, yes. He may know that he can cast to IFoo, but not
At the risk of belaboring a point I think is irrelevant to the original
question: but why would that matter?

Because I want to know that I can cast to ICountable whenever I know
that something implements IList<T>. I already know that I can cast to
IEnumerable, and I'm using that in the code - ICountable would be the
equivalent but to retrieve the count.
If as a matter of the actual definition for IList<T> it needs to inherit
ICountable, then sure...inherit away. But if all we've got is code that
wants an ICountable, then it shouldn't care at all whether that's part of
IList<T> or something else.

And indeed it wouldn't.
If you already know for sure it's created as
IList<T>, then even better, should you happen to also want to use the
instance as an IList<T>.

But as I only have a compile-time reference as "object" I would have to
go to a fair amount of nasty reflection work in order to use any of the
IList said:
But that doesn't stop you from reinterpreting the instance reference
in two different ways to support two different interfaces.

My point is that I may well be able to guarantee (through other pieces
of code) that I'm passed in IList<T> implementations, but *not* be able
to guarantee that I'm being pass in ICountable implementations - unless
IList said:
Again, I don't disagree that it's simpler to keep one variable than two,
but I don't see this as implying that the best solution is to create a
whole new type just for that purpose. And of course, I definitely don't
see that as a required approach to the original question.

Depending on the exact scenario, it may well not be. It may well be
that turning it into a generic method and letting type inference do its
thing would work equally well.
[...]
I'm not sure we know enough about the OP's scenario to say for sure.

As is often the case, it's true that we can't be sure we know enough. I
agree with that.

But I feel reasonably confident enough to make statements based on the
question as stated. In particular, it seems pretty clear to me that he's
not looking to do any casting; he's got an object instance he wants to
pass, but without the generic decoration. In other words, the caller
already knows we're dealing with the generic type.

If his post has misrepresented the situation, then yes...there may be more
to the solution than just creating a generic method, and perhaps even
there would be a justification for creating a new non-generic interface.
But I think that given the code posted so far, a generic method is a more
appropriate approach than creating a new type.

Well, at least he's got two options now...
 
J

Jon Skeet [C# MVP]

To me, that suggests a goal specifically served by just the inheritance
you're proposing. That is, you're not just trying to pass a
type-parameterless instance of IList<T> to something, but rather you have
a specific desire to connect the two interfaces. You specifically want
one fact to imply the other.

Yes - but part of the reason for that precisely so that when I know
I can't disagree with that as a motivation for inheriting the interface.
After all, to me that's what the inheritance is all about. But that seems
separate from the goal of being about to get a count from the object.

Getting the count is what I happen to want to do, and it's an operation
which doesn't require any information about the type of the element -
so to me it makes sense to be able to get that information without
knowing anything at compile time.
But is it really so much more important to be able to cast without a check?

I'm all for taking advantage of implicit information when possible, but
imposing interface implementations arbitrarily seems unnecessary.

It's not asking the implementors of the IList<T> to do anything they're
not already doing - it's just pushing one member up the interface
inheritance hierarchy. I agree that asking them to implement extra
functionality for the sake of this kind of situation would be a bad
idea. (Obviously I'm not proposing that ICountable is actually added at
this point, by the way - just that it would have been nice to have
before, and free from the perspective of implementation.)
That's true. And it's debatable whether IList<T> should have included as
part of its own definition members that don't actually need the type T.
Perhaps from the outset, it would have made more sense to factor out the
non-type-dependent parts into a non-generic interface inherited by
IList<T>.

That's precisely what I've been proposing. I don't know if you're a Red
Dwarf fan, but there's an episode called "White Hole" which has the
perfect conversation here :)
But with respect to the original question, I don't see that being the
proposal. To me, an IFoo as a non-generic version of IFoo<T> would be
just like IFoo<T> except without type. That is, the type parameter would
be replaced by "Object" everywhere.

In some cases that would be reasonable (or by another non-generic
interface, by the way - so an IEnumerable<T> might be replaced by
IEnumerable in the API) but in some cases it would be worth just
including the non-type-specific parts.
I see that proposal as fundamentally different from what you're talking
about.

Now, granted...the proposals to make a non-generic interface that IFoo<T>
inherits are about as vague as the original question was. I'm making
assumptions about how that IFoo interface would be declared, and those
assumptions might not be the intent of the original proposal. But at the
very least, those assumptions should be corrected by those proposing to
create a new type. :)

Without knowing more about the OP's requirements, I don't know if this
suggestion would be any use at all in the first place - but if it is,
it might be a "whole API in nongeneric form" situation or a "restricted
API" situation. The latter is certainly simpler, as it means no extra
work on the part of the interface implementations.
 
P

Pavel Minaev

When you specify a type, e.g. as a return type or a parameter type,
you can only specify one type. You can't say "It has to take something
which implements both ICountable and IList<T>" - not unless you
introduce another generic type parameter just for that purpose, which
certainly isn't always practical.

Why isn't it practical? So far as I can see, it's precisely what is
needed. Overly verbose, perhaps, especially if we don't actually need
to refer to T anywhere else (wish we had a placeholder like Java's "?"
there), but on the whole, it makes sense. Generic parameter covariance
and contravariance at declaration site, as promised in C# 4.0, is of
limited utility (because if we take IList<T> for example, that T will
be invariant - so we don't get anything), and the only other approach
to proper granularity is to have one interface per method/property....

The bigger deal there is the lack of contravariance - the "? super T"
constraint in Java. Without it, as it stands, it's simply impossible
to write a generic method that takes "any IList<> to which an instance
of T can be added".
 
M

Marc Gravell

Jon: "so what is it?"

Jon/Pete: re knowing it is an IList<T>, but not knowing the T - this
happens a lot if your code is processing rtti from other types. As it
happens, Jon and I are looking at the same problem (in different
ways), so I know very well that in this case you can't know the T -
but this is very common anyway when working with reflection /
ComponentModel.

For my own version of the problem, I cheat : my /real/ code uses
IList<T>, and the other code uses MakeGenericMethod to invoke the
typed version with the appropriate T; this works well, but it is only
appropriate if you are doing pre-processing (it isn't something you'd
want to do repeatedly in a tight loop for example).

Jon: "so what is it?"

Marc
 
J

Jon Skeet [C# MVP]

Marc Gravell said:
Jon: "so what is it?"

It's a *white* hole, sir.
Jon: "so what is it?"

I believe we've just reached the middle of this conversation.


(From memory, last watched about 10 years ago, so don't hold me to the
exact words...)
 
J

Jon Skeet [C# MVP]

Pavel Minaev said:
Why isn't it practical?

Well, for one thing that information can't be captured by the compiler
at the client side. If I declare a generic method like this:

T Foo() where T : IList<T>, ICountable

then in the caller, if I want to use both aspects of it, I will need to
cast at some point, which will mean a runtime check, even though really
we know that it will always be valid. It's a pain.

In addition, introducing extra levels of generic methods etc ends up
with code which can be very confusing. Just making one interface derive
from another - particularly when it adds no cost to the implementer -
is much simpler.
 
P

Pavel Minaev

Well, for one thing that information can't be captured by the compiler
at the client side. If I declare a generic method like this:

T Foo() where T : IList<T>, ICountable

then in the caller, if I want to use both aspects of it, I will need to
cast at some point, which will mean a runtime check, even though really
we know that it will always be valid. It's a pain.

Technically, you can capture T in the above example with complete
(and static) type decorations if you just pass on the returned value
to your own generic method at call site - but I agree that it is
rather a mess. One could probably write helpers, like this:

struct GenericResult<T1, T2>
{
public T1 o1;
public T2 o2;

public GenericResult(T o) where T: T1, T2
{
o1 = o; o2 = o;
}
}
// overloads for up to N generic parameters ...

But it is still messy. This is only a problem with return types of
methods though, not parameters.

It would really be much more convenient if we could just get & and |
combinators on types. One can dream...
 

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