Reputation: 1388
Why can't generics be used like this? Declare common open type or interface and separate logic for each concrete type directly:
interface IOpen<T>
{
T A { get; }
}
class Concrete<int> : IOpen<int>
{
public int A => 42;
public string B => "42";
}
interface IWorker<T>
{
void Do(IOpen<T> item);
}
class WorkerInt : IWorker<int>
{
public void Do(Concrete<int> item)
{
Console.WriteLine(item.A);
Console.WriteLine(item.B);
}
}
How to avoid that restriction in the code above? If I create class ConcreteInt : IOpen<int>
then WorkerInt
would not implement IWorker<T>
. Thanks.
Upvotes: 0
Views: 986
Reputation: 117009
You can't define class Concrete<int>
with <int>
- it's like you're trying to override the normal definition of int
with a new generic type called int
. But then in the class you're trying to actually return an int
.
So it should look like:
class Concrete : IOpen<int>
{
public int A => 42;
public string B => "42";
}
But now the class WorkerInt
would have to look like this:
class WorkerInt : IWorker<int>
{
public void Do(Concrete item)
{
Console.WriteLine(item.A);
Console.WriteLine(item.B);
}
}
But IWorker<int>
must implement void Do(IOpen<T> item)
and even though Concrete
implements IOpen<T>
you can't use void Do(Concrete item)
because it is more restrictive than void Do(IOpen<T> item)
.
So you must define it this way:
class WorkerInt : IWorker<int>
{
public void Do(IOpen<int> item)
{
Console.WriteLine(item.A);
//Console.WriteLine(item.B);
}
}
But that makes item.B
no longer work as IOpen<int>
doesn't have a B
property.
The only way to make this work is to change IWorker
to be this:
interface IWorker<T, R> where T : IOpen<R>
{
void Do(T item);
}
Then WorkerInt
can be this:
class WorkerInt : IWorker<Concrete, int>
{
public void Do(Concrete item)
{
Console.WriteLine(item.A);
Console.WriteLine(item.B);
}
}
Upvotes: 2
Reputation: 91515
Generics aren't meant as a placeholder for type inference. Generics are meant to allow containers like List
, Dictionary
, Tree
, etc. to contain any type without needing to cast to and from Object
. They make containers more statically robust.
If you want to be able to pass a limited set of types to some kind of processor, then use overloaded methods.
public void Do(int item) { ... }
public void Do(string item) { ... }
This way, the method signature is what determines which method to use.
Additionally, if you're trying to make different worker objects, you could have a similar set of static overloaded methods that instantiate the workers and call the Do()
method.
class WorkerManager {
public static void DoWork(int item) {
var worker = new WorkerInt();
worker.Do(item);
}
public static void DoWork(string item) {
var worker = new WorkerString();
worker.Do(item);
}
}
Upvotes: 0