Say we have a non generic base interface, with a generic inheriting interface:
public interface IFoo { }
public interface IBar<T, K> : IFoo {
K Do(T t);
}
public class BarImpl : IBar<Type, AnotherType> {
public AnotherType Do(Type type) {
return new AnotherType(type);
}
}
I need to create a factory which returns an IFoo instance, but using the returned instance I need to be able to call the derived types Do(T), which isn't available.
public class FooFactory() {
IFoo Get() {
// simplified, in reality i am returning the correct
// type by checking the generic interface
// types to get an object from a stored list
// of implementations
return BarImpl();
}
}
// Now in another class
public void DoFoo() {
IFoo iFoo = new FooFactory().Get();
// Need to be able to call iFoo.Do(Type) but cannot
}
The only way I have been able to get this to work is to create a dynamic object, instead of IFoo, and then call Do() - which does work in my case but I lose some type safety which i'd prefer to keep.
My question is can I re-engineer this to be able to get access to the derived interfaces method, whilst still being able to maintain a list (and subsequently factory method return type) of IFoo????
You expect or want type safety, but think about it this way:
Do
, Get
needs to return a type which defines that method. IFoo
does not have it, but IBar<T, K>
does. Get
however returns an IFoo
object which is not guaranteed to be a IBar<T, K>
. Get
would make sure that only a IBar<T, K>
is returned, there is no way the type system would know this without actually returning that type . Do
method, the type would be unclear: You need to pass it an object of type T
. But the returned IFoo
or IBar<T, K>
does not necessarily use the same type T
that you wanted to pass to Do
. Get
would provide this (like “Get me an IBar<T, K>
that accepts the type T
”) and the type system would have a way to reflect this, then this still wouldn't say anything about K
. For a known T
, it could still be an IBar<T, int>
, or an IBar<T, string>
. And there is actually no way to know that without actually having the concrete type. Do
. My point is that you only need generic types, when you actually have a reason to maintain a concrete type. Usually if you call a generic method or a method of a generic type from another non-generic method, then you either have a discrete set of types you're working with, or you don't actually need the generic type information.
So maybe you're better off introducing a non-generic IBar
type here:
interface IBar
{
object Do(object t);
}
interface IBar<T, K> : IBar
{
K Do(T t);
}
public class BarImpl : IBar<Type, AnotherType>
{
public AnotherType Do(Type type)
{
return new AnotherType(type);
}
public object Do(object t)
{
return Do((Type) t);
}
}
Then you could make Get
return an IBar
instead, and you have a way to call Do
.
Btw. this pattern is used pretty commonly in the BCL, eg IEnumerable<T>
and IEnumerable
.
You could add a object DoIt()
method to IFoo
, then BarImpl
would implement it:
public object DoIt()
{
return Do(typeof(T));
}
The problem here is that you would then need to cast the return of DoIt
to the actual type. But you won't know apriori what that is.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.