Difference between generic declaration and providing class parameter - c#

What differences are there between declaring:
GenericClass<T> genericInst = new GenericClass<T>();
and
GenericClass<baseClass> temp = new GenericClass<baseClass>();
Here the GenericClass is defined to be for where T : baseClass
GenericClass contains a generic list
private List<T> vals = new List<T>();

It seems to me, and please correct me if I'm wrong, that you are taking 'where T : baseClass' as if it were a default for type T to be a baseClass?
If so, this is not the case, the specialization where T : baseClass means that the type T must be baseClass or derived from baseClass (or implement if it were an interface instead of a class).
Thus, if you had:
public class GenericClass<T> where T : baseClass
{
}
Then you can say:
var x = new GenericClass<baseClass>();
Or
var y = new GenericClass<SomethignDerivedFromBaseClass>();
But you could not say:
var z = new GenericClass<int>();
Since int does not inherit from baseClass.
The only way to actually use T in the instantiation above is if you were actually calling that line of code from within the GenericClass<T>:
public GenericClass<T> where T : baseClass
{
void SomeMethod()
{
GenericClass<T> genericInst = new GenericClass<T>();
}
}
Or from another context where T is already known to be a sub-class of baseClass.
UPDATE
Based on your comments, it sounds like you're wondering that if you had:
public class GenericClass<T> where T : baseClass
{
public List<T> Items { get; set; }
...
}
Whether you could add things derived from baseClass into the list, and the answer is yes-ish. The class GenericClass<T> could be declared for any T that inherits from baseClass. But the List<T> would still be strongly typed to type T.
That is given these:
public class BaseClass { }
public class SubClass : BaseClass { }
A GenericClass<BaseClass> could hold both BaseClass and SubClass in it's List<T> since T will be BaseClass.
But a GenericClass<SubClass> will have a List<T> where T will be SubClass and thus can only hold items of SubClass or inheriting from it.

Related

Is there a way to declare members of an abstract base class that are the type of the derived class?

Suppose I have an abstract base class that I want to declare members in that will match the type of the classes that derive from this base class.
public abstract class BaseClass
{
protected BaseClass parent;
}
public class DerivedClass1 : BaseClass
{
// parent could be of type DerivedClass2
}
public class DerivedClass2 : BaseClass
{
// parent could be of type DerivedClass1
}
This won't work because the parent field in each derived class can be anything that derives from BaseClass. I want to ensure that the parent field in DerivedClass1 can only be of type DerivedClass1. So I'm thinking maybe I should use generics.
public abstract class BaseClass<T> where T : BaseClass<T>
{
protected T parent;
}
This may seem confusing and circular, but it does compile. It's basically saying parent is of type T which has to derive from the generic BaseClass. So now a derived class can look like this:
public class DerivedClass : BaseClass<DerivedClass>
{
// parent is of type DerivedClass
}
The problem is that I have to enforce the type-matching myself when I declare DerivedClass. There's nothing stopping someone from doing something like this:
public class DerivedClass1 : BaseClass<DerivedClass2>
{
// parent is of type DerivedClass2
}
Does C# have a way of doing this so that the type of a member declared in the base is sure to match the derived type?
I think this is similar to what this C++ question was trying to ask: Abstract base class for derived classes with functions that have a return type of the derived class
If I understand your requirements correctly, you have a series of classes with an inheritance relationship, and you wish to arrange them in a tree structure where each instance has a parent of the same type and only of the same type. It's an interesting problem.
After noodling with this for a bit, may I suggest you separate the requirements into two parallel but related object graphs, so that you have
A set of classes with an inheritance relationship
A set of classes that can contain any of the classes from the first set, and have type-strict parents and children.
First, let's declare the first set of classes that inherit from each other. Ignore the Node bit for now.
public class BaseClass
{
public Node ContainerNode { get; set; }
}
public class DerivedClass1 : BaseClass
{
}
public class DerivedClass2 : BaseClass
{
}
These classes can't do much but it's just an example.
Now let's set up another set of classes that can participate in a tree. Each element in the tree is called a Node.
//Basic node
public class Node
{
}
//A node that can contain a T (which must be a BaseClass or derived from one)
public class Node<T> : Node where T : BaseClass
{
public T Parent { get; set; }
public T This { get; set; }
public Node(T innerClass)
{
this.This = innerClass;
innerClass.ContainerNode = this;
}
}
Now we have everything we need to enforce the type safety you seek. We can create classes in your inheritance hierarchy like this:
var child1 = new Node<DerivedClass1>(new DerivedClass1());
var parent1 = new Node<DerivedClass1>(new DerivedClass1());
child1.Parent = parent1.This;
Let's see what happens if we mistakenly mix up DerivedClass1 and DerivedClass2:
var child2 = new Node<DerivedClass2>(new DerivedClass2());
var parent2 = new Node<DerivedClass1>(new DerivedClass1()); //Oops
child2.Parent = parent2.This; //Does not compile
So as you can see, the Parent property is now typesafe.
Now all that stuff ^^^^ looks kind of messy, so let's clean it up by adding a few helper methods.
public class Node
{
public T GetParent<T>() where T : BaseClass
{
return ((Node<T>)this).Parent;
}
static public Node<T> Create<T>(T innerClass) where T : BaseClass
{
return new Node<T>(innerClass);
}
static public T GetParent<T>(T child) where T: BaseClass
{
return child.ContainerNode.GetParent<T>();
}
static public implicit operator T (Node<T> input)
{
return input.This;
}
}
Now, since the compiler can infer the <T> arguments, our declarations are much neater:
var child1 = Node.Create(new DerivedClass1());
var parent1 = Node.Create(new DerivedClass1());
child1.Parent = parent1;
And it's easy for any of the derived classes to find its own parent:
public class DerivedClass1 : BaseClass
{
protected DerivedClass1 Parent
{
get
{
return Node.GetParent(this); //This is type safe!
}
}
}
One objection to all this is that you don't want coders to deal with this Node layer. Well, they don't, because we set up an implicit cast:
Node<DerivedClass1> a = Node.Create(new DerivedClass1());
DerivedClass1 b = a; //Works!!! And is type-safe.
Full working code on DotNetFiddle.

c# .net 4.0 Covariant vs Contravariant

I'm trying to get something working and struggling with the below when using Contravariance. My understanding is Covariance is where you can return a derived type from a base type. Contravariance is where you can pass in a derived type from a base type as an argument into a class.
So I have the below interface (contravariant):
public interface IBase<in T> where T: BaseModel
{
void Process(T model);
}
I then have an abstract class
public abstract class Base<T>: IBase<T> where T: BaseModel
{
public virtual void Process(T model)
{
// throw new System.NotImplementedException();
}
}
and another concrete class
public class Parent: Base<ParentModel>
{
public override void Process(ParentModel model)
{
// throw new System.NotImplementedException();
}
}
Considering the generic type is only ever used as an input and not a return type, I don't see why I cannot do the below:
IBase<BaseModel> baseContravariant = new Parent();
// This doesn't compile. I will eventually have a list of IBase<BaseMode> to which I'd like to pass in different parent instances.
I have another example using covariance which is below and works fine.
public interface IBase<out T> where T : BaseModel, new()
{
T ProcessAndGet();
}
Abstract
public abstract class Base<T>: IBase<T> where T: BaseModel, new()
{
public virtual T ProcessAndGet()
{
var result = new T() as BaseModel;
// More shizzle here
return (T)result;
}
}
Concrete
public class Parent : Base<ParentModel>
{
public override ParentModel ProcessAndGet()
{
var x = base.ProcessAndGet();
return x;
}
}
Now I can do
IBase<BaseModel> baseInstance = new Base<BaseModel>();
IBase<BaseModel> derived = new Parent();
baseInstance = derived;
There's more code to the above examples but I've removed it for ease of reading (hopefully!) :-)
Contravariance in this case means that you need to pass in types that are of the specified type or one that is "more specialised" (=> derive from the base type).
Since your Parent implementation in your first example can only process ParentModel, it is invalid to pass in a BaseModel instance. Trying to do new Parent().Process(new BaseModel()) also would not compile. So it is invalid to cast it to IBase<BaseModel>. (assuming ParentModel is a subclass of BaseModel).
In this case the contravariance model is easier to reason about by thinking that an IBase<in T> "consumes a T". So an IBase<ParentModel> "consumes ParentModels". This means it can only be passed values that are instances of ParentModel or can be treated as one (effectively only subclasses).
In your second example you are using <out T>, which is "covariant". This can be described as "it produces instances of T". So a class that "produces" a ParentModel is automatically a "producer" of BaseModel as well: since ParentModel can be cased to BaseModel, IBase<ParentModel> can be casted to IBase<BaseModel> as well.

Pass Generic Type up the Inheritance Tree

I have the following classes:
abstract class Foo<T>
abstract class BaseClass : Foo<BaseClass>
class DerivedOne : BaseClass
class DerivedTwo : BaseClass
Using this structure, all class that derive from BaseClass inherit from Foo<BaseClass>. I want to be able to set the generic type of T different in each derived class
For example, in DerivedOne I want the class to be Foo<DerivedOne> but in DerivedTwo I want the class to derive from Foo<DerivedTwo>.
Is there any way to pass the generic type up the inheritance tree?
I tried doing something like this (which doesn't work).
abstract class Foo<T>
abstract class BaseClass<T> : Foo<T>
class DerivedOne : BaseClass<DerivedOne>
class DerivedTwo : BaseClass<DerivedTwo>
Edit: changed generic types to show that they are passing in themselves as generic types
Edit #2: Here is a code sample of the actual classes I am using:
public abstract class DBObject<T>
where T : DBObject<T>, new()
{
//the generic type is for this method, so I can create an object from a database query
public static T Create(DataRow dataRow)
{
Type T = MethodBase.GetCurrentMethod().DeclaringType;
T obj = new T();
foreach (var field in obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
if (dataRow.Table.Columns.Contains(field.Name))
{
Object safeObj = Convert.ChangeType(dataRow[field.Name].ToString(), field.FieldType);
field.SetValue(obj, safeObj);
}
}
foreach (var field in obj.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
{
Console.WriteLine(field.Name + "=" + field.GetValue(obj));
//propInfo.SetValue(obj, value, null);
}
return obj;
}
}
public abstract class Contact<T> : DBObject<T>
where T : Contact<T>
{
//field and methods ommitted...
}
public class Person : Contact<Person>
{
//fields and methods ommitted...
}
public class Company : Contact<Company>
{
//fields and methods ommitted...
}
The classes can then be used in such a manner:
Person person = Person.Create(/* DataRow from a query result */);
I get your code to compile if you add the new() constraint to Contact<T>:
public abstract class Contact<T> : DBObject<T>
where T : Contact<T>, new()
{
//field and methods ommitted...
}
This is necessary since generic constraints aren't inherited.

Can the type of the current class be used as the value of a generic type parameter?

Can something like this be accomplished using C#?
public abstract class BaseClass
{
public abstract IInterface<T> CreateEditor() where T: the_actual_type_of_this_instance;
}
Example usage:
var instance = new DerivedClass();
var editor = instance.CreateEditor(); // IInterface<DerivedClass>
No, you can't do that - partly because it wouldn't make sense at compile time. Consider a slight change to your code:
BaseClass instance = new DerivedClass();
var editor = instance.CreateEditor();
What could the compiler infer the type of editor to be? It only knows about BaseClass, so it would have to return an IInterface<BaseClass>. Depending on whether or not T in IInterface<T> is covariant, that could be valid for something which actually implemented IInterface<DerivedClass> or it might not be.
You might want to make your base class generic instead:
public abstract class BaseClass<T> where T : BaseClass<T>
{
public abstract IInterface<T> CreateEditor();
}
public class DerivedClass : BaseClass<DerivedClass>
{
...
}
There are two problems with this:
It doesn't work when you go more than one level deep; if you need subclasses of DerivedClass, you'll have issues
It doesn't prevent malicious abuse of the pattern, e.g. public class NastyClass : BaseClass<DerivedClass>
... but in many cases it's quite practical.

Generic Constraint to allow casting from interface to implementation

I have a small class that implements a dictionary that maps from the type of an interface to an implementation of that interface that extends from a base class. Unfortunately the abstract base class does not implement the interfaces, so once in the dictionary, there seems to be no way to associate the two. There is another method in this class that is dependent on storing the objects as BaseClass (in fact, most of my class is dependent on that--the getter into the dictionary is somewhat of a convenience).
private readonly Dictionary<Type, BaseClass> dictionary;
public void Add<T>(BaseClass base)
{
if (!(base is T)) // How to get rid of this check?
{
throw new ArgumentException("base does not implement " + typeof(T).Name);
}
this.dictionary.Add(typeof(T), base);
}
public T Get<T>()
{
BaseClass base;
this.dictionary.TryGetValue(typeof(T), out base);
return (T)(object)base; // How to get rid of (object) cast?
}
Are there any clever constraints I can use to remove the (base is T) check, the cast to object, or both?
Here is the class setup, for reference:
class BaseClass { }
interface IThing { }
class MyClass : BaseClass, IThing { }
dict.Add<IThing>(new MyClass());
IThing myClass = dict.Get<IThing>();
The only way to get the compile-time enforcement you're looking for would be if you have compile-type knowledge of the derived type being added.
For example, if you also specify a type parameter for the class being added then you could constrain that the class implement the interface type parameter:
public void Add<TInterface, TClass>(TClass #base)
where TClass : BaseClass, TInterface {
this.dictionary.Add(typeof(TInterface), #base);
}
So you could do this:
MyClass ok = new MyClass();
dict.Add<IThing, MyClass>(ok);
But not this:
class MyClassNotIThing : BaseClass { }
MyClassNotIThing notOk = new MyClassNotIThing();
dict.Add<IThing, MyClassNotIThing>(notOk);
Aside from that, generic constraints don't offer a means by which to constrain that a known type (i.e. BaseClass) inherit from a generic type parameter.
Here is the solution I ended up using. There are a few tricks that can make the Add() safe without the check (see the link in a comment to cokeman19's answer), but I opted not to do that as I find this code a bit cleaner.
interface IThing { }
abstract class BaseClass
{
internal T AsInterface<T> where T : class
{
return this as T;
}
}
class MyClass : BaseClass, IThing { }
class DictionaryClass
{
private readonly Dictionary<Type, BaseClass> dictionary;
public void Add<T>(BaseClass base)
{
if (base is T)
{
dictionary.Add(typeof(T), base);
}
}
public T Get<T>() where T : class
{
return dictionary[typeof(T)].AsInterface<T>();
}
}
Note that this solution does allow calls like:
myClass.AsInterface<IThingItDoesntImplement>()
but this returns null and I made the function internal to prevent strange uses anyway.

Categories

Resources