I have a base class that has methods that use a generic type in C#, I then have other classes that inherit from these, I want to specify the type in the parent class to avoid angle brackets everywhere...
Here's a sample method from my base class class CBaseHome
public List<T> fetchAll<T>(CBaseDb db, bool includeEmpty = true) where T : CBaseTable, new()
{
List<T> retVal = new List<T>();
...
return retVal;
}
I the have a parent class that inherits from this class, (without overriding this function)
In the class that then consumes this I have the following code...
List<student> students = new limxpoDB.Home.student().fetchAll<student>(db, false);
so the Home.student class here inherits the CBaseHome class, and student inherits the CBaseTable...
I'd like to be able to say in the Home.student class that the only valid generic type for that class is student so that my consuming code looks like...
List<student> students = new limxpoDB.Home.student().fetchAll(db, false);
I realise here that the difference is minute, but I also use this library in some VB>Net code where it looks terrible...
Any ideas?
Thanks
Generic type parameters on a method cannot be imposed by a child class. So if I have:
public class Parent {
public List<T> GetStuff<T>() { ... }
}
I can not do:
public class Child : Parent {
// This is not legal, and there is no legal equivalent.
public List<ChildStuff> GetStuff<ChildStuff>() { ... }
}
What you can do is make the parent class generic, rather than it's method:
public class Parent<T> {
public List<T> GetStuff() { ... }
}
public class Child : Parent<ChildStuff> {
// GetStuff for Child now automatically returns List<ChildStuff>
}
Related
I have a parent class like this:
public class WebserviceResultPerNode
{
public List<DBMappingResult> mapTable { get; set; }
public static WebserviceResultPerNode newInstanceFromError(ErrorResponse error)
{
return new WebserviceResultPerNode
{
mapTable = null,
responseCode = error.responseCode,
responseMessage = error.responseMessage
};
}
}
It have some derived classes such as below:
public class WebserviceInsertResultPerNode : WebserviceResultPerNode
{
}
Now I want to make derived classes like WebserviceInsertResultPerNode such that when I call WebserviceInsertResultPerNode.newInstanceFromError() their return type be same as derived class not parent class. Currently return type of newInstanceFromError is type of parent class, i.e. WebserviceResultPerNode.
I want to know are there any ways to override WebserviceInsertResultPerNode.newInstanceFromError such that its return type be WebserviceInsertResultPerNode but I don't need to initialize fields of parent class without the need to rewrite them.
How can I rewrite my code to achieve this goal?
You can simply achieve this by using reflection, providing child classes will always have a parameter-less constructor:
public class WebserviceResultPerNode<T> where T : WebserviceResultPerNode<T>, new()
{
public static T NewInstanceFromError(ErrorResponse error)
{
return new T() { … };
};
}
Then the descendant class will look like this:
public class MyWebServiceResult : WebserviceResultPerNode<MyWebServiceResult> { … }
However, I do strongly recommend decomposing the factory method into a separate factory class for the sake of separation of concerns.
Consider this made-up example...
public abstract class CollectionItem<TSelf> {
protected CollectionItem(ICollection<TSelf> siblings)
=> Siblings = siblings;
public ICollection<TSelf> Siblings { get; }
}
public class Foo : CollectionItem<Foo>{
public Foo()
: base(new FooCollection){}
}
public class FooCollection : ObservableCollection<Foo>{
}
With the above, Foo now has a Siblings property. However, there are three problems with this.
I have to repeat the redundant Foo in the generic
Siblings itself isn't typed to the actual collection type, but rather the interface.
I have to actually pass in an instance of the Siblings collection
Solving for #2 and #3, I made this change...
public class CollectionItem<TSelf, TSiblings>
where TSiblings : ICollection<TSelf>, new() {
protected CollectionItem()
=> Siblings = new TSiblings();
public TSiblings Siblings { get; }
}
but I still have to pass in the seemingly redundant Foo as the first type parameter, like this...
public class Foo : CollectionItem<Foo, FooCollection>{
}
In Swift, you have an implicit Self datatype which always represents the type of the current instance, meaning if Self is used in a base class, it's actually a stand-in for the data type of the subclass. Think of it as an implicit generic if you will.
Having that in C# would allow me to do something like this...
public class CollectionItem<TSiblings>
where TSiblings : ICollection<Self>, new() { // Note it uses 'Self' here
protected CollectionItem()
=> Siblings = new TSiblings();
public TSiblings Siblings { get; }
}
public class Foo : CollectionItem<FooCollection>{
}
public class Laa : CollectionItem<LaaCollection>{
}
In the above, for instances of Foo, Self refers to Foo. For instances of Laa, Self refers to Laa. No need to pass the redundant type parameters.
So does C# have anything similar?
I've been trying to do something which I hoped would be simple, but turned otherwise.
I have a base class:
public class EntityBase
{
}
and two classes that inherit from it:
public class EntityA : EntityBase
{
}
public class EntityB : EntityBase
{
}
I want to use a container type that will wrap
An instance of EntityBase
A number of children which are other instances of the container type.
I want this container expose the exact type of the EntityBase instance it contains, so I use C# generics. But I could not manage to convince C# compiler to define a list of the container type (which has a type parameter now):
public class EntityNode<T> where T : EntityBase
{
private T _node;
private List<EntityNode<EntityBase>> _children = new List<EntityNode<EntityBase>>();
public EntityNode(T pNode)
{
_node = pNode;
}
public void AddChild(EntityNode<T> pNode)
{
//_children.Add(pNode); //this is not going to work...
}
public T Root
{
get { return _node; }
set { _node = value; }
}
}
Is it possible to allow EntityNode to contain a list which in turn contains EntityNode<EntityA>, EntityNode<EntityB> and EntityNode<EntityBase> instances?
What about using List<EntityNode<T>> instead of List<EntityNode<EntityBase>>:
private List<EntityNode<T>> _children = new List<EntityNode<T>>();
I have base class for my entities
public class Entity<T> where T : Entity<T>, new()
{
public XElement ToXElement()
{
}
public static T FromXElement(XElement x)
{
}
}
I have to use this strange construction Entity<T> where T : Entity<T>, because i want static method FromXElement to be strongly-typed
Also, i have some entities, like that
public class Category : Entity<Category>
{
}
public class Collection : Entity<Collection>
{
}
How can i create a generic list of my entities, using base class?
var list = new List<Entity<?>>();
list.Add(new Category());
list.Add(new Collection());
You can't with that definition. There is no "common base class" between Category and Collection (other than object, of course).
If there were, say if Entity<T> were defined as:
public class Entity
{
}
public class Entity<T> : Entity where T : Entity<T>, new()
{
public XElement ToXElement()
{
}
public static T FromXElement(XElement x)
{
}
}
then you could do
var list = new List<Entity>();
list.Add(new Category());
list.Add(new Collection());
But what would that buy you?
Create a marker interface:
public interface IAmAGenericEntity { }
public class Entity<T> where T : IAmAGenericEntity, new()
// ...
public class Category : Entity<T>, IAmAGenericEntity
// ....
var list = new List<IAmAGenericEntity>();
// ...
From the lack of an abstract marker on Entity, I assume that To/FromXElement use reflection and should work for any subtype of Entity. I recommend that you structure your classes as follows:
public class Entity
{
public XElement ToXElement() { ... }
protected static T FromXElement<T>(XElement x)
where T : Entity
{
...
}
}
public class Category : Entity
{
public static Category : FromXElement(XElement x)
{
return FromXElement<Category>(x);
}
}
The "boilerplate" is minimal, and it doesn't require that you creatively circumvent the type system. You don't have to worry about the lack of a common base, or about manual conversions. If you like, you can eliminate the boilerplate entirely and just construct your objects directly from Entity:
public class Entity
{
public XElement ToXElement() { ... }
public static T FromXElement<T>(XElement x)
where T : Entity
{
...
}
}
In essence, what you're doing is implementing a type class, which C# does not directly support. There are a number of ways to work around this lack, but I usually find them to be more trouble than they're worth, especially when it comes to static methods. If C# supported static extension methods, it would be simple, but alas it does not.
You can define a non-generic class to be the base class of all entity classes
public class Entity
{
}
and make Entity inherit Entity
public class Entity<T> : Entity where T : Entity<T>, new()
{
}
Now you can create the list of entities as:
var list = new List<Entity>();
You can solve this problem by adding a non-generic version of the class
class Entity
{
// methods
public T As<T>()
{
if (this is T) return (T)this;
throw new InvalidCastException();
}
}
class Entity<T> : Entity where T : Entity<T>, new()
class Cathegory : Entity<T> {}
and then create the list of the base class:
var list = new List<Entity>()
list.Add(new Cathegory());
Then, if you want to call a "generic specific" operation, you need to call the "As" function or simply cast the object.
I have 1 abstract class that is calling a static method which up until now didn't require any parameters. This has recently changed. In reality the static method exists in another class and sets the value of BaseMessageDirectory, but in this example below I have simplified things...
So now I want to create my derived classes in such a way that they can initialize some required properties in the parent class during the inheritance, is this possible?
For example....
public abstract class ParentClass
{
protected string BaseMessageDirectory;
protected ParentClass(EnumOperationType operationType)
{
if(operationtype == 1)
{
BaseMessageDirectory = "one";
}
else
{
BaseMessageDirectory = "two";
}
}
}
Yes, you can define a constructor, and all child classes will have to call it:
public class Child : ParentClass
{
public Child() : base(EnumOperationType.One) { ... }
}