I have a problem with generics. I have written a generic class. I derive other classes from this class.
Finally I would like to use this derived class in another class but I haven't found working solution how to get it working.
Here is my simplified example:
// Generic base class
public class Information<T>
{
public T StatusCode;
public bool Changed;
}
public class Status1 : Information<Status1.Codes>
{
public enum Codes { None = 0, }
public string AdditionalStatusInformation;
public Status1()
{
StatusCode = Codes.None;
}
}
public class Status2 : Information<Status2.Codes>
{
public enum Codes { OK = 0, }
public Status2()
{
StatusCode = Codes.OK;
}
}
Everything good so far. I am sending and reading this information using Json and this approach works for both receiver and transmitter. Works fine with Status1 and Status2 classes.
Finally I have generic ErrorReporter class where I would like to use my Status1 or Status2 class. Seems this is not possible.
public class ErrorReporter<T> where T : Information<T>
{
public readonly T Info = Activator.CreateInstance<T>();
public void Update()
{
if (Info.Changed)
{
Console.WriteLine(Info.StatusCode.ToString());
Console.WriteLine(JsonConvert.SerializeObject(Info));
}
}
}
Seems there is no way to instantiate this class properly.
I tried these
new ErrorReporter<Status1>()
new ErrorReporter<Status1.Codes>()
new ErrorReporter<Information<Status1.Codes>()
I am getting
The type 'TestApp.Program.Status1' cannot be used as type parameter 'T' in
the generic type or method 'TestApp.Program.ErrorReporter<T>'.
There is no implicit reference conversion from 'TestApp.Program.Status1' to
'TestApp.Program.Information<TestApp.Program.Status1>'.
or similar error message.
I probably should move my ErrorReporter class to Information class.
But what is correct way to instantiate new object from my ErrorReporter class? Is it even possible?
The problem is that you're trying to use T
for two purposes:
StatusCode
on it)Information<T>
)Now you could just make ErrorReporter
generic in two type parameters instead:
public class ErrorReporter<TSource, TCode> where TSource : Information<TCode>
{
public readonly TSource Info = Activator.CreateInstance<TSource>();
public void Update()
{
if (Info.Changed)
{
Console.WriteLine(Info.StatusCode.ToString());
Console.WriteLine(JsonConvert.SerializeObject(Info));
}
}
}
Then you could use:
new ErrorReporter<Status1, Status1.Codes>()
Or you could make it generic in just the code type, but avoid constructing the source by reflection:
public class ErrorReporter<T>
{
// You could expose this as a property if you want. I would
// advise against exposing it as a field
private readonly Information<T> source;
public ErrorReporter(Information<T> source)
{
this.source = source;
}
public void Update()
{
if (Info.Changed)
{
Console.WriteLine(source.StatusCode.ToString());
Console.WriteLine(JsonConvert.SerializeObject(source));
}
}
}
And construct it as:
var reporter = new ErrorReporter<Status1.Codes>(new Status1());
See more on this question at Stackoverflow