Issue when inheriting abstract generic class - c#

I have an abstract generic class:
public abstract class A<T> where T : class, new()
{
public A (IEnumerable<T>_Data)
{
this.Data = _Data;
}
private IEnumerable<T>_data;
public IEnumerable<T> Data
{
get { return _data; }
set { _data = value;}
}
}
Then when I inherit from that class:
public class B<T> : A<T> where T : class, new()
{
}
I get an error:
There is not argument that corresponds to the required formal parameter '_Data' of 'A.A(IEnumerable)'
in the 'B' class.

You need to inherit A<T>, not A:
public class B<T> : A<T> where T : class, new(){
}
Furthermore public A(_Data) is not constructor, which I assume you wanted. You need public A<T>(IEnumerable<T> _Data)instead.
Last but not least you have to create a constructor for B that can invoke any of those from A. So either define a parameterless constructor in A or one in B with IEnumerable<T> as argument:
public class B<T> : A<T> where T : class, new()
{
public B<T>(IEnumerable<T> data) : base(data) { ... }
}

As it says in the error, it cannot create the base class because you did not provide the correct constructor in B. change it to this if you want to pass any args
public class B<T> : A<T> where T : class, new(){
public B(IEnumerable<T> data):base(data) {
}
}
Otherwise, new your data in the constructor and and pass it to base.

Either provide a public parameterless constructor on your base class or as others suggested make a call to your base class constructor by passing IEnumerable<T> from the derived class

Related

How to constrain a generic collection to both a class name and an interface

Given public class BaseClass
that has derived classes, where a number of those follow the form
public class DerivedClass : BaseClass, ISpecificInterface
is there a way of specifying a collection that applies to just the derived classes that implement that interface?
For example, something like
public List<BaseClass where ISpecificInterface> myList; or
public List<BaseClass : ISpecificInterface> myList;
You can only constrain generic parameters, not generic arguments. So you'll need:
public class DerivedClassWithInterfaceListContainer<TDerived>
where TDerived : BaseClass, ISpecificInterface
{
public List<TDerived> MyList { get; set; }
}
You may want to inherit List<T> for this instead:
public class DerivedList<TDerived> : List<TDerived>
where TDerived : BaseClass, ISpecificInterface
{
}
And then you can use it as property type:
public DerivedList<SomeDerivedClass> MyList { get; set; }
Point being: you can only declare the list as containing one type. So if you want a list that can hold any class derived from BaseClass and implementing ISpecificInterface, you must do so in a method:
// either ISpecificInterface _or_ BaseClass
private List<ISpecificInterface> myList;
public void AddToList<TDerived>(TDerived toAdd)
where TDerived : BaseClass, ISpecificInterface
{
myList.Add(toAdd);
}
You could then combine this:
public class DerivedList : List<ISpecificInterface>
{
public new void Add<TDerived>(TDerived toAdd)
where TDerived : BaseClass, ISpecificInterface
{
this.Add(toAdd);
}
}
But now someone can cast your DerivedList to IList<ISpecificInterface> and call Add() on that, with an object implementing ISpecificInterface but not inheriting from BaseClass.

Forcing a derived class to have a constructor with a signature

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

Calling Generic Method on Generic Field?

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);
}
...
}

Overriding a method returning a generic class

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();
}
}

How to have a sealed constructor?

I have a baseclass which has public contructors.
The baseclass is not sealed and is not abstract.
There is one constructor which I desire to be sealed. Is this possible?
My current attempt results in syntax error saying the constructor cannot be sealed.
public sealed MyBase(string someParam)
Additional:
I wish to be able to instantiate the base class directly and have access to the sealed constructor. Derived classes cannot use that constructor via the derived constructors.
E.g.
public MyDerived() : base(string cant_access_my_sealed_constructor)
You can't do that. If the constructor is public, you can call it from constructors of derived classes. But you can do something close – you can have a private constructor and a public static method that calls it:
class MyBase
{
private MyBase(string someParam)
{
// some code
}
public static MyBase Create(string someParam)
{
return new MyBase(someParam);
}
protected MyBase() // or some other protected or public constructor
{ }
}
class MyDerived : MyBase
{
public MyDerived()
: base("foo") // won't compile, as requested
{ }
}
All constructors are "sealed" in that they cannot be "overridden." They can only be called from the constructor in a child class.
If you are hoping to prevent child classes from having a constructor with the same signature, that cannot be done.
Based on the additional information you added to the post, it sounds like what you want to do is make your constructor private, as Kyle suggested. This will prevent the child class from calling the constructor, but it won't prevent it from taking the same types of arguments:
public class Foo
{
private Foo(string s){
}
// Allowed
public Foo() : this("hello") {
}
}
public class Bar : Foo
{
// Allowed
public Bar(string s) : base(){
}
// Not allowed
public Bar(string s) : base(s){
}
}
If you want to prevent the constructor from being called by inherited classes, just mark it private.
Constructors aren't inherited by a child class, you have to explicitly call a base constructor if desired.
This code will call the base class' no-parameter constuctor when an instance of the child class is instantiated. Without it, the base class' constructor won't be called when creating a new instance of the child class.
public class A
{
public A()
{
}
}
public class B : A
{
public B()
: base()
{
}
}

Categories