Reputation: 6222
Is there a way to have a generic field in a class to specialize to a specific type in the constructor?
For example:
class concreteClass1
{
private int a;
public concreteClass1( int a)
{
this.a = a;
}
}
class concreteClass2
{
string b;
public concreteClass2(string b)
{
this.b = b;
}
}
class A<T>
{
private T field;
public A(int x)
{
field = new concreteClass1(x); //error here CS0029
}
public A(string y)
{
field = new concreteClass2(y); //error here CS0029
}
}
So T
can be either concreteClass1
or concreteClass1
and their respective ctors will have different signatures.
Upvotes: 2
Views: 105
Reputation: 29252
I would refactor this to use dependency injection. That way the class doesn't contain code to create other classes that it depends on, like myConcreteField = new ConcreteA<T>(4);
. Dependency injection is used to keep code from getting tied into difficult knots like this.
(Your example is very, very abstract, which makes it a little difficult. If you use class names like "Concrete" and "Implementation" then it makes the answer harder to read because we use those same words to describe concepts.)
Instead, whatever that Concrete
thing is, declare an interface, like
public interface ISomethingThatTheOtherClassNeeds<T>
{
public int MySomething {get;set;}
}
public class SomethingThatTheOtherClassNeeds : ISomethingThatTheOtherClassNeeds<string>
{
public int MySomething {get;set;}
}
Then in your Implementation
class:
class Implementation<T>
{
private readonly ISomethingThatTheOtherClassNeeds<T> _something;
public Implementation(ISomethingThatTheOtherClassNeeds<T> something)
{
_something = something;
}
void DoSomething()
{
Console.Write(_something.MySomething.ToString());
}
}
The difference is that instead of being responsible for creating whatever that class is, it's passed to Implementation
in the constructor. Implementation
doesn't even know what the class is - it just knows that it matches the interface.
This is especially helpful if those other classes in turn depend on more classes. If you're creating them by calling new
in your class then that class has to know how to create those classes.
Then to wire it up you would use a dependency injection container like Windsor, Unity, Autofac, and many more. That's not very commonly done with console applications, but I'm guessing this is more experimental than real.
Upvotes: 1
Reputation: 5606
Well this was a bit tricky due to having to convert types. Maybe this will work for you?
class Program
{
static void Main(string[] args)
{
var myImplementation = new Implementation<int>(4);
var myImplementation2 = new Implementation<string>("Hello World");
Console.WriteLine(myImplementation.myConcreteField); // outputs 4!
Console.WriteLine(myImplementation2.myConcreteField); // outputs Hello World
}
}
abstract class MyAbstract<T>
{
public T MySomething;
public MyAbstract(T something)
{
MySomething = something;
}
}
class ConcreteA<T> : MyAbstract<T>
{
public ConcreteA(int something) : base((T)Convert.ChangeType(something, typeof(T)))
{
}
}
class ConcreteB<T> : MyAbstract<T>
{
public ConcreteB(string something) : base((T)Convert.ChangeType(something, typeof(T)))
{
}
}
class Implementation<T>
{
public MyAbstract<T> myConcreteField;
public Implementation(T a)
{
myConcreteField = new ConcreteA<T>(4);
}
void DoSomething()
{
Console.Write(myConcreteField.MySomething.ToString());
}
}
Upvotes: 1