in my Silverlight 4 application I started creating and using some generics and now I stumbled upon the following problem:
In a non-generic class, I have a abstract method, that returns a generic class:
public abstract class DTO_Base()
{
public abstract ServiceModelBase<ServiceNodeBase> CreateBusinessObject();
}
The generic class is defined in the following way:
public abstract class ServiceModelBase<RootNodeType> where RootNodeType : ServiceNodeBase
Naturally, from DTO_Base derived classes will have to override the CreateBusinessObject method:
public class DTO_Editor : DTO_Base
{
public override ServiceModelBase<ServiceNodeBase> CreateBusinessObject()
{
// the object to return have to be of type ServiceModelEditor
// which is derived from ServiceModelBase<ServiceNodeEditor>
// public class ServiceModelEditor : ServiceModelBase<ServiceNodeEditor>
// ServiceNodeEditor is derived from ServiceNodeBase
// public class ServiceNodeEditor : ServiceNodeBase
ServiceModelEditor target = new ServiceModelEditor()
...
Functions to populate the 'target'
...
return target;
}
}
The line return target; causes an error, stating that it isn't possible to implicitly convert the type ServiceModelEditor in ServiceModelBase<ServiceNodeBase>. Also, an explicit conversion via target as ServiceModelBase<ServiceNodeBase> doesn't work.
How would I have to implement this method to work?
Try this:
public interface IDTO<Node> where Node : ServiceNodeBase
{
ServiceModelBase<Node> CreateBusinessObject();
}
public abstract class DTO_Base<Model,Node> : IDTO<Node>
where Model : ServiceModelBase<Node>
where Node : ServiceNodeBase
{
public abstract Model CreateBusinessObject();
#region IDTO<Node> Members
ServiceModelBase<Node> IDTO<Node>.CreateBusinessObject()
{
return CreateBusinessObject();
}
#endregion
}
public class DTO_Editor : DTO_Base<ServiceModelEditor, ServiceNodeEditor>
{
public override ServiceModelEditor CreateBusinessObject()
{
// the object to return have to be of type ServiceModelEditor
// which is derived from ServiceModelBase<ServiceNodeEditor>
// public class ServiceModelEditor : ServiceModelBase<ServiceNodeEditor>
// ServiceNodeEditor is derived from ServiceNodeBase
// public class ServiceNodeEditor : ServiceNodeBase
ServiceModelEditor target = new ServiceModelEditor();
return target;
}
}
I have faced a similar problem before and the only thing reasonable to do is to make the core base class generic also. You can remove the Model generic parameter (and the interface) and it will look a little less scary, but you loose visibility on the functionality of ServiceModelEditor outside of the method.
As it is, you've got to return a ServiceModelBase<ServiceNodeBase>. One option is to make your base class generic:
public abstract class DtoBase<T> where T : RootNodeType
{
public abstract ServiceModelBase<T> CreateBusinessObject();
}
Then:
public class DtoEditor : DtoBase<ServiceNodeBase>
{
public override ServiceModelBase<ServiceNodeBase> CreateBusinessObject()
{
...
}
}
If you are using .Net 4.0 I suggest you use interfaces to define your ServiceModelBase and specify an out variance modifier on that interface generic type:
class ServiceNodeBase { }
class ServiceNodeEditor : ServiceNodeBase {/*implementation*/}
//
interface IServiceModelBase<out RootNodeType>
where RootNodeType : ServiceNodeBase {
}
class ServiceModelEditor : IServiceModelBase<ServiceNodeEditor> {
/*implementation*/
}
//
abstract class DTO_Base {
public abstract IServiceModelBase<ServiceNodeBase> CreateBusinessObject();
}
class DTO_Editor : DTO_Base {
public override IServiceModelBase<ServiceNodeBase> CreateBusinessObject() {
return new ServiceModelEditor();
}
}
Related
How do I force all derived classes of an interface to have a constructor with a signature? This doesn't work:
public interface Constructor<T> where T : Constructor<T>, new()
{
Constructor(T);
}
public interface IParameters
{
}
public interface IRule : Constructor<IParameters>
{
//IRule (IParameters); must exist
}
You can't, not via an interface. But you can sort of get at it with an abstract class. Similar to what the accepted answer here describes, try:
public abstract class MustInitialize<T>
{
public MustInitialize(T parameters)
{
}
}
public class Rule : MustInitialize<IParameters>, IRule
{
IParameters _parameters;
public Rule(IParameters parameters)
: base (parameters)
{
_parameters= parameters;
}
}
You can't force a specific constructor signature.
Even with an abstract class as demonstrated in Mark's answer, you can only force the constructor of the abstract class, but nothing is stopping the author of the derived class to do something like this:
public class Rule : MustInitialize<IParameters>, IRule
{
public Rule()
: base (new Parameters())
{
// Assuming Parameters is a class that implements the IParameters interface
}
}
However, you can force dependency injection by using method (setter) injection:
public interface IMethodInjection<T>
{
void Method(T injected);
}
I think you can design your base class like the following example:
public abstract class MyBase
{
private MyBase()
{
}
public MyBase(string a)
{
}
}
public class MyDerived : MyBase
{
public MyDerived(string a) : base(a)
{
}
}
You can even delete the private constructor if its not needed
I have a class that inherits an abstract class which inherits another abstract class. I can define the most-super class as being generic just fine, but I don't know how to define the middle class as being generic before I express the actual type I want in the final ListResults class.
internal abstract class LowerCommand<T> {
public abstract void Execute();
public abstract List<T> ExecuteList();
}
// currently gives error for `T`
internal abstract class HigherCommand : Lowercommand<T> {
// ... defines other stuff, nothing to do with
// already instantiated methods or T ...
}
class ListResults : HigherCommand<Results>
{
public override void Execute() {...}
public override List<Results> ExecuteList() {...}
}
Thanks for your help.
You still need to define the generic type parameter T on the definition of HigherCommand so it can in turn properly define LowerCommand.
internal abstract class LowerCommand<T> {
public abstract void Execute();
public abstract List<T> ExecuteList();
}
// Note that HigherCommand require a declaration of `T`
internal abstract class HigherCommand<T> : LowerCommand<T> {
// ... defines other stuff, nothing to do with
// already instantiated methods or T ...
}
class ListResults : HigherCommand<Results>
{
public override void Execute() {...}
public override List<Results> ExecuteList() {...}
}
I have the following classes (some of them are in the PRISM framework and cannot be changed):
public abstract class NetworkEventBase<T> : CompositePresentationEvent<T> where T : NetworkEventPayload { }
public class NetworkEventPayload { }
public class TestEvent : NetworkEventBase<TestPayload> { }
public class TestPayload : NetworkEventPayload { }
// the following classes are PRISM classes:
public class CompositePresentationEvent<TPayload> : EventBase { }
public abstract class EventBase { }
Now I need to convert an instance of TestEvent to its base class NetworkEventBase inside a decorator for IEventAggregator. IEventAggregator looks like:
public interface IEventAggregator
{
TEventType GetEvent<TEventType>() where TEventType : EventBase, new();
}
Now in my decorator I try to convert like this:
public class MessageBusAdapterInjectorDecorator : IEventAggregator {
...
public TEventType GetEvent<TEventType>() where TEventType : EventBase, new()
{
var aggregatedEvent = this.eventAggregator.GetEvent<TEventType>();
var networkEvent = aggregatedEvent as NetworkEventBase<NetworkEventPayload>;
if (networkEvent != null)
{
networkEvent.MessageBusAdapter = this.messageBusAdapter;
}
return aggregatedEvent;
}
}
However, networkEvent is always null, even when the runtime type of aggregatedEvent is TestEvent.
You seem to hope that the class called NetworkEventBase<T> would be covariant in T. But generic classes can't be covariant in C# (generic interfaces can).
See other threads on this issue.
I have the following and at some point I need to create Failures for Validations. We suppose each type deriving from Validation has one and only one type deriving from Failure<T> where T is the aforementioned implementation of Validation.
As I have a growing number of implementations of Validation, I need to be able to instantiate the right type deriving from Failure<T>, and call the link method on it within a method that looks like
void recordFailureForValidation(Validation v) {
Type failureType = dict[v.GetType()];
Object failure = Activator.CreateInstance(failureType);
// how do I call failure.link(v) ?
}
At Runtime, a dictionary gives me the type deriving from Failure<T> given T.
I am able to instantiate Failure<T> (Failure1, Failure2, etc...), but I can't find how to call link on the public field reference of my newly created Failure instance (by making all uses that made sense to me of GetMethod, MakeGenericMethod, Invoke, etc...)
public class MyReferenceClass<T>
where T : Object, new() {
public void link(T arg) { ... }
}
public abstract class Failure<T>
where T : ValidationRule, new() {
...
public MyReferenceClass<T> reference;
...
}
public class Failure1 : Failure<Validation1> {
}
public class Failure2 : Failure<Validation2> {
}
public abstract class ValidationRule {
...
}
public class ValidationRule1 : ValidationRule {
...
}
public class ValidationRule2 : ValidationRule {
...
}
link is private since you do not specify a different accessibility. Make it public or internal:
public class MyReferenceClass<T>
where T : Object, new() {
public void link(T arg) { ... }
}
then you can call it from Failure<T> through the reference property:
public abstract class Failure<T>
where T : ValidationRule, new()
{
protected T Validation {get; set;};
public MyReferenceClass<T> reference;
}
public class Failure1 : Failure<Validation1>
{
public void Test()
{
this.reference.link(Validation);
}
}
Let Failures implement a non generic IFailure interface as well as a generic one in the same manner as IEnumerable and IEnumerable<T>
Create an abstract factory method within ValidationRule that has to be implemented by each concrete Validation
public ValidationRule1 : ValidationRule
{
public override IFailure ToFailure()
{
return new Failure1(this);
}
...
}
I have a generic class with a class constraint on it.
public class MyContainer<T> where T : MyBaseRow
MyBaseRow is an abstract class which I also want to contain a member of some flavour of MyContainer.
public abstract class MyBaseRow
{
public MyContainer<MyBaseRow> ParentContainer;
public MyBaseRow(MyContainer<MyBaseRow> parentContainer)
{
ParentContainer = parentContainer;
}
}
I am having problems with the constructors of classes inherited from MyBaseRow eg.
public class MyInheritedRowA : MyBaseRow
{
public MyInheritedRowA(MyContainer<MyInheritedRowA> parentContainer)
: base(parentContainer)
{ }
}
Won't allow MyInheritedRowA in the constructor, the compiler only expects and only allows MyBaseRow. I thought the generic class constraint allowed for inheritance? What am I doing wrong here and is there any way I can redesign these classes to get around this?
Many thanks in advance for any responses.
Basically, you can't use generics that way, because the covariance system doesn't work that way with classes. See here: http://geekswithblogs.net/abhijeetp/archive/2010/01/10/covariance-and-contravariance-in-c-4.0.aspx
You can however use an interface like this:
public interface MyContainer<out T> where T : MyBaseRow {
}
And that code will compile.
You can make a covariant generic interface (C#4.0):
public interface IContainer<out T> where T : MyBaseRow
{
}
public class MyContainer<T> : IContainer<T> where T : MyBaseRow
{
}
public abstract class MyBaseRow
{
public IContainer<MyBaseRow> ParentContainer;
public MyBaseRow(IContainer<MyBaseRow> parentContainer)
{
ParentContainer = parentContainer;
}
}
public class MyInheritedRowA : MyBaseRow
{
public MyInheritedRowA(IContainer<MyInheritedRowA> parentContainer)
: base(parentContainer)
{ }
}