imagine this layout of classes i use for building a tree structure:
class Treenodebase
{
Treenodebase Parent{get;set;}
IEnumerable<Treenodebase> Children {get;set;}
}
class Specialtreenode : Treenodebase
{
string SpecialProperty{get;set;}
public string ParentsSpecialProperty()
{
return Parent.SpecialProperty; //here I'd need casting?!
}
}
class Othertreenode : Treenodebase
{
string OtherProperty {get;set;}
}
I use the subclasses to build seperate trees throughout my program. that means each Specialtreenode only ever has a parent of type Specialtreenode, and also children of type Specialtreenode.
The snipped is very simplified. The base class has many more properties (like IsSelected and IsExpanded) and methods (think 'Ancestors' or 'Siblings' and the like) and the subclasses too.
Can I somehow utilize type parameters here to avoid casting within each of the subclasses? Or would that always involve my subclasses not inheriting from the baseclass?
You could do something like this:
class Treenodebase<T> where T : Treenodebase<T>
{
public T Parent{get;set;}
public IEnumerable<T> Children {get;set;}
}
class Specialtreenode : Treenodebase<Specialtreenode>
{
string SpecialProperty{get;set;}
public string ParentsSpecialProperty()
{
return Parent.SpecialProperty;
}
}
Of course, this eliminates the non-generic Treenodebase type, which could be good or bad. If you have a lot of utility methods that don't really care what implementation you use, you might want to make Treenodebase<T> either extend a non-generic base class or implement a non-generic interface. On the other hand, you might find it easier to just make all your utility methods be generically typed as well. It depends on how you're using the tree in code.
Related
I have a basic structure of generic's classes
public class Parent<T> where T : Parent<T>
{
Action<T> Notify;
}
public class Child : Parent<Child>
{
}
And I want to have a list so that Child objects can be put there
List<Parent> parents = new List<Parent>();
In java I just can write List<? extends Parent> and all Parent's subclasses easily can be added to the list. Is there any alternative of this in C#?
You can't do the same thing as Java, because in Java, generics use type erasure and break variance. Essentially, your Java code turns everything into List<object>, and hopes for the best. The only reason why List<?> is better than List<Object> is that not everything is an Object in Java - in C#, you can put an integer inside a List<object> just fine. Mind, a List<int> will perform much better than List<object>, if you can afford it - that's one of the big reasons why generics were originally added to C#.
C# is a bit stricter than that. You can't do anything like new List<Parent<T>>() that would allow any kind of Parent<T>. If you had more limited requirements, you could use a variant interface instead, but that wouldn't work with List<T> for obvious reasons.
Your only real option is to make the base class non-generic. The user of your list can't know anything about the T in advance anyway, so any part of the Parent interface that returns or takes T wouldn't be useful without casting anyway (Java does the casting for you, but it's still casting - neither Java's nor C#'s generics are powerful enough for what you're trying to do).
public abstract class Parent
{
// The common methods
public abstract int Id { get; }
}
public abstract class Parent<TChild> : Parent, IEnumerable<TChild>
{
// The methods that are TChild-specific - if you don't need any of those, just drop
// this class, the non-generic one will work fine
private List<TChild> children;
public void Add(TChild child) => ...
public TChild this[int index] => ...
}
public class Child : Parent<TChild>
{
...
}
Now to get a list of all possible children, you can use
var list = new List<Parent>();
And when you need to get e.g. all the Child items, you can do
var children = list.OfType<Child>();
Just for completeness sake, you can get similar behavior to Java's with C#'s dynamic. But I'm not even going to show any sample of that - dynamic is a useful tool, but mainly for more dynamic typing problems. It's overkill for something as simple as this, and trades compile-time issues for run-time issues.
In general, if you ever use Parent<T> directly, it should be in a generic method - e.g. an extension method that has some common functionality for all Parent<T>s. You can't instantiate a generic type that doesn't have all the type arguments known at the time in C#.
Declaration List<Parent> parent; does not compile, since it requires type argument.
And when you say, public class Child : Parent<Child> it inherits Parent<Child> and not Parent<T>
So List<Parent<Child>> list; will only accept objects of Child class, and not of any other subclass of Parent.
Still you can achieve what you need with help of an interface as below: working fiddle here
public class Program
{
public static void Main()
{
List<Parent<IParent>> parentList = new List<Parent<IParent>>();
parentList.Add(new Child1());
parentList.Add(new Child2());
}
}
public class Parent<T>
{ }
public interface IParent
{ }
public class Child1 : Parent<IParent>, IParent
{ }
public class Child2 : Parent<IParent>, IParent
{ }
I have an interface IRecordBuilder and an abstract class Query with a field protected IRecordBuilder recordBuilder and a method public abstract IList<IRecords> GetRecordsFromResults();.
In Query child classes constructors, I specify a recordBuilder concrete type depending on which child class I am in, for exemple :
recordBuilder = new RecordsPerMonthBuilder(); //RecordsPerMonthBuilder implements IRecordBuilder
I would like to use my recordBuilder field in the implementations of the abstract method above, but the properties in the implementations of IRecordBuilder remains unknown at compile time and i can't use them.
Besides transfering recordBuilder from mother class to each child classes and instantiate it there with the proper type, is there a way to make the polymorphism work here ?
Here are the explanations in code format :
public interface IRecordBuilder
{
IRecords BuildRecord();
}
public class RecordsPerMonthBuilder : IRecordBuilder
{
public IRecords BuildRecord()
{
if(Foo != null) return new FooRecord(Foo); // class FooRecord : IRecord
return null;
}
public string Foo {get; set;}
}
public abstract class Query
{
protected IRecordBuilder recordBuilder;
public abstract IList<IRecords> GetRecordsFromResults();
}
public sealed class ConcreteQuery: Query
{
public ConcreteQuery()
{
RecordBuilder = new RecordsPerMonthBuilder();
}
public override IList<IRecords> GetRecordsFromResults()
{
var recordsList = new List<IRecords>();
recordBuilder.foo = "foo"; // IRecordBuilder does not contain a definition for foo
recordsList.Add(RecordBuilder.BuildRecord());
return recordsList;
}
}
I see three possible solutions for this:
Option 1: In your child class, cast the builder to the concrete type (since the child class created it, it knows the concrete type). If you do that, you might want to make the recordBuilder field readonly and pass it to the base constructor to ensure at compile time that its type cannot be changed.
Option 2: In your child class, keep an additional "strongly typed" reference to the record builder. (In fact, why do you even need the "interface typed" reference at all?)
public sealed class ConcreteQuery: Query
{
private RecordsPerMonthBuilder myBuilder;
public ConcreteQuery()
{
myBuilder = new RecordsPerMonthBuilder();
RecordBuilder = myBuilder;
}
public override IList<IRecords> GetRecordsFromResults()
{
var recordsList = new List<IRecords>();
myBuilder.foo = "foo";
recordsList.Add(myBuilder.BuildRecord());
return recordsList;
}
}
Option 3: Make your base class generic:
public abstract class Query<TBuilder> where TBuilder : IRecordBuilder
{
protected TBuilder RecordBuilder;
public abstract IList<IRecords> GetRecordsFromResults();
}
public sealed class ConcreteQuery : Query<RecordsPerMonthBuilder>
{
...
}
One area of confusion is that your Query class depends explicitly on one implementation of IRecordBuilder, RecordsPerMonthBuilder. The interface IRecordBuilder doesn't have a Foo property, but Query depends on the Foo property. Query is hard-coded to only use RecordsPerMonthBuilder.
It's difficult to see the intent. One way to clear it up is to make sure that any interaction between Query and an implementation of IRecordBuilder is defined in IRecordBuilder. Query should depend on the interface and shouldn't call any properties or methods that aren't in that interface.
If only one implementation of IRecordBuilder requires a Foo, then that value shouldn't be coming from your Query class because Query doesn't know that IRecordBuilder needs a Foo. It shouldn't know what an implementation of IRecordBuilder needs, only what it does.
Here's a way to move it around. You'll see this pattern a lot.
public abstract class Query
{
protected IRecordBuilder RecordBuilder { get; private set; }
protected Query(IRecordBuilder recordBuilder)
{
RecordBuilder = recordBuilder;
}
public abstract IList<IRecords> GetRecordsFromResults();
}
Now it will never know what the implementation of IRecordBuilder is. That's good. It's now impossible for it to depend on anything that's not in the IRecordBuilder interface. Now Query depends on an abstraction, applying the Dependency Inversion principle.
What about RecordsPerMonthBuilder? It depends on a value, Foo. Will every implementation of IRecordBuilder need that? If so you could add it to the interface:
IRecords BuildRecord(string foo);
But if only one implementation needs that value then it shouldn't come from Query, because Query shouldn't know the difference between one IRecordBuilder and another. I can't answer that more specifically because I don't know what Foo is.
Another suggestion: If the inheritance between Query and ConcreteQuery gives you any grief, just don't use inheritance. Sometimes trying to use inheritance creates complications and doesn't give us any benefit in return.
I currently have a small object hierarchy that looks like this:
public class BaseClass {
// this class is empty and exists only so the others can extend it and share the
// same base type
}
public class ChildA : BaseClass {
public Subject<AssociatedClassA> Results;
}
public class ChildB : BaseClass {
public Subject<AssociatedClassB> Results;
}
In my design I would like to enforce that every class that extends from BaseClass should contain a Subject<SomeType> called Results. I'm wondering if there is a way that I can move Results into the base class or an interface such that I can supply the generic type for the Subject when constructing the base class. For example, it would be awesome if I could do something like this:
ChildA<AssociatedClassA> instance = new ChildA<AssociatedClassA>();
Or even better since there should really only be one template parameter that matches with ChildA if when I constructed it that could be taken care of for me:
ChildA instance = new ChildA();
// Results is automatically set to Subject<AssociatedClassA>
I'm stuck trying to implement this now as if I try to move Results into the base class the Subject requires a template parameter which I can't necessarily supply. There could potentially be more than 2 derived classes and I don't like the idea that someone extending this system has to know to add Results manually to each child class.
Following the suggestions of the 2 answers below this solves my desire to move Results into the base class, however I've run into another issue in that I was hoping to be able to use BaseClass as a generic parameter to methods such that any of the derived classes could be used. For example:
public void ProcessBaseClass(BaseClass base) {
// base could be ChildA or ChildB here
}
This no longer works since BaseClass now requires a type argument. Is there any way that I can have the best of both worlds here or am I stuck due to my design choices?
If appropriate, you can make the parent generic:
public class BaseClass<T> {
public Subject<T> Results;
}
public class ChildA : BaseClass<AssociatedClassA> {
}
public class ChildB : BaseClass<AssociatedClassB> {
}
You can make the base class itself generic:
public class BaseClass<T> {
public T Results { get; protected set; }
}
I have two custom objects, lets say Cat and Dog. I want to create an observable collection that can hold either of these objects, as they are very similar. Can I use base classes to do this?
If so, would you mind providing a quick example.
And if I do use a base class, does that mean if I want to use common fields, I should put those into the base class?
EDIT: I'm hoping to then bind a WPF datagrid to the properties of these objects. I don't know if it's possible to bind a datagrid in WPF to two different kind of objects...
Yes, in that case you can use a base class:
public class Pet
{
public int Id { get; set; }
public string Name { get; set; }
public void Run() { }
}
public class Cat: Pet
{
public string Meow()
{
return "Meow";
}
}
public class Dog :Pet
{
public string Bark()
{
return "Whow";
}
}
Notice however, that when you place instances of both classes in one collection you can access only members of the base class.
So this code is valid:
var collection = new ObservableCollection<Pet> {new Cat(), new Dog()};
foreach (var pet in collection)
{
pet.Run();
}
but you cannot use methods Meow() and Bark() unless you use explicit casting.
Be careful with moving too many members to the base class - in the example above Meow() doesn't make sense for the Dog and Bark() for the Cat. If you need to use some method specific to the derived class you could check the type with:
pet.GetType()
and then cast object to the derived type:
var cat = (Cat)pet;
cat.Meow();
Yes. You can use a base class say animal. And yes if they have common fields such as name, type, etc.. they can go in there.
class Animal {
public String name;
}
Then just extend that. But you can also extend the functionality.
class Dog extends Animal {
public void bark();
}
Now anything that asks for something of type Animal can receive Dog.
public void addToCollection(Animal animal)
addToCollection(new Dog());
This is actually the backbone for Java's Object.
Yes to the properties, that's sort of the point of base classes. You express the commonality in the base and the specificity in the derived classes. As for whether the base class is the best place for an observable collection, well, it depends. You need to give some more insight into the need and the expected usage. It's doable though.
Check out ObservableCollection<T> also.
I've read an excellent article on MSDN regarding Generics in C#.
The question that popped in my head was - why should i be using generic constraints?
For example, if I use code like this:
public class MyClass<T> where T : ISomething
{
}
can't I switch ALL references of T in this class with ISomething?
What's the benefit of using this approach?
You ask, "can't I switch ALL references of T in this class with ISomething?" So I think you mean to compare:
public class MyClass<T> where T : ISomething
{
public T MyProperty { get; set; }
}
With:
public class MyClass
{
public ISomething MyProperty { get; set; }
}
In the second example, MyProperty is only guaranteed to be an instance of ISomething. In the first example, MyProperty is whatever T is, even if that is a specific subtype of ISomething. Consider a concrete implementation of ISomething:
public class MySomething : ISomething
{
public string MyOtherProperty { get; set; }
}
Now, if we use the first, generic, example, we could have:
MyClass<MySomething> myClass = new MyClass<MySomething>();
Console.WriteLine(myClass.MyProperty.MyOtherProperty);
On the other hand, if we used the second example, we wouldn't be able to access MyOtherProperty since it's only known to be an ISomething:
MyClass myClass = new MyClass();
Console.WriteLine(myClass.MyProperty.MyOtherProperty); // Won't compile, no property "MyOtherProperty"
On a different note, the reason these type constraints are useful is that you can refer to MyProperty (type T) and access members of ISomething. In other words, if ISomething were declared like:
public interface ISomething
{
public string SomeProperty { get; set; }
}
Then you could access MyProperty.SomeProperty. If you omitted the where T : ISomething then you wouldn't be able to access SomeProperty since T would only be known to be of type object.
Type Safety. For example, suppose you're creating a container. You can pass in something to that container and retrieve it in the proper form without having to do any casts later by parameterizing the container. You're simply defining constraints on the types of things that you're willing to store in your container.
Here's an example of the difference, by just using List<>
Image list wouldn't be generic but it would just use IListElement everywhere it used the generic instead. Now Imagine you have an object that's something like this.
class Element : IListElement
{
public string Something { get; set; }
}
now I could just do list.Add(element); and there wouldn't be a difference with a real List<Element>. However when I retreive data it's a different story, if I use the list that uses IListElement then I have to cast my data back so I can get the Something out of it. Thus i'd have to do:
string s = ((Element)list[0]).Something;
while with the generic I can just do:
string s = list[0].Something;
saves a lot of trouble, ofcourse it goes a bit further than that but I think you can get the idea from this.
Well for a start, you can call methods defined in ISomething within the code for the generic method / methods on the generic class. If T was allowed to be any type then this would not be possible (although you could always do some runtime casting).
So it allows you to enforce compile-time constraints on what T can be and therefore rely on these constraints when you write the code - turning runtime errors into compile time errors.
Yes you can use ISomething in place of T , but that will manually close the generic type to an ordinary class. It wont be a generic type any more. By using T, you keep the type open to as many ISomething subtypes as you want. Code reuse without compromising type safety is the key benefit here. For example if you use a Stack of ISomethings, you can push any ISomething onto the stack but a pop has to occur with a downcast to the actual subtype of ISomething for it to be useful. Downcasting creates a potential failure point, which will not be there in a generic Stack<T> where T:ISomething
Consumer of your class gets the benefit of increased type-safety, among others.
class Widget : IPokable { }
// No generics
Widget w = (Widget)list[0]; // cast can fail
// With generics
Widget w = list[0];
Without generics, if list was containing IPokable objects, cast is still necessary.
Class you're implementing gets the benefit of using specific methods on the generic object.
class PokableList<T> where T : IPokable {
public T PokeAndGet() {
currentObj.Poke();
return currentObj;
}
}
Perhaps this simple example might help.
If I have these classes:
public class ListOfCars<T> : List<T> where T : Car { }
public abstract class Car { }
public class Porsche : Car { }
public class Bmw : Car { }
...and then if I write this code:
var porsches = new ListOfCars<Porsche>();
// OK
porsches.Add(new Porsche());
//Error - Can't add BMW's to Porsche List
porsches.Add(new Bmw());
You can see that I can't add a BMW to a Porsche list, but if I just programmed off of the base class it would be allowed.