Really bizarre C# generics question - c#

This code compiles but looks very strange.
I have a typical and simple parent/child relationship here which is implemented using generics in a very strange way.
But I can't seem to find any other way of doing it.
class SampleObject<T> //I don't want to make this a generic but am forced to
{
//The SampleContainer this object is in
//This must be located in this base class
public SampleContainer<T> Parent { get; set; }
}
class SpecificObject : SampleObject<SpecificObject>
//SampleObject<SpecificObject> !!? This is the bizzare bit
//It seems really strange but necessary for compilation to work
{
}
//A class to contain a List of objects derived from SampleObjects
class SampleContainer<T>
{
public List<T> List;
}
class Start
{
public void Test()
{
SampleContainer<SpecificObject> container = new SampleContainer<SpecificObject>();
SpecificObject o = new SpecificObject(); //create an object
container.List.Add(o); //add it to the list
o.Parent = container; //set its parent
}
}
Can this code be simplified?

This seems to work without the type.
Is this what you were looking for?
class SampleObject //I don't want to make this a generic but am forced to
{
//The SampleContainer this object is in
//This must be located in this base class
public SampleContainer<SampleObject> Parent;//{ get; set; }
}
class SpecificObject : SampleObject
//SampleObject<SpecificObject> !!? This is the bizzare bit
//It seems really strange but necessary for compilation to work
{
}
//A class to contain a List of objects derived from SampleObjects
class SampleContainer<T>
{
public List<T> List;
}
class Start
{
public void Test()
{
SampleContainer<SampleObject> container = new SampleContainer<SampleObject>();
SpecificObject o = new SpecificObject(); //create an object
container.List.Add(o); //add it to the list
o.Parent = container; //set its parent
}
}

In the MSDN documentation, it states that:
When deriving from a generic base
class, you must provide a type
argument instead of the base-class's
generic type parameter:
public class BaseClass<T>
{...}
public class SubClass : BaseClass<int>
{...}
It's probably a constraint that the C# designers set up in the compiler. They require that a derived type must specify the type of the generic argument at compile time. I'm not quite sure why.

Generics can create some unwieldy class hierarchies. However, the syntax for SpecificObject : SampleObject does make sense, since you're stating that the object has a parent relationship. The only other way I could see you do this, would be to split out the hierarchy with an interface. It doesn't buy much, but it may help clarify the intent.
interface IHasParent<T>
{
T Parent { get; set; }
}
public class SpecificObject : IHasParent<SpecificObject>
{
public SpecificObject Parent { get; set; }
}
If you're concerned about how verbose your collection is, you can tame the angle brackets a bit by using:
public SpecificObjectContainer : Container<SpecificObject>
{
}

Related

Downcasting baseclass into derived generic type C#

I am struggling with an issue related with conversion between generic, possibly it's an easy one.
Basically I want to create a list of base class and add into it multiple classes.
public interface IQueryEngineDependency
{
public IEnumerable<QueryDependencyDetail> GetDependencies<>();
}
public abstract class QueryDependencyDetail
{
public int Order { get; set; }
}
public class QueryDependencyDetail<TEntity, TKey> : QueryDependencyDetail
where TEntity : BaseEntity<TKey>
{
public virtual Func<TEntity, object> Key { get; set; }
public IQueryable<TEntity> Data { get; set; }
public Func<TEntity, object> JoinKey { get; set; }
public Expression<Func<TEntity, bool>> WhereClause { get; set; }
}
Problem
I have a class, per example, that implements the interface shown above but I am figuring it out the right way to implement this.
public class TestQueryDependency : IQueryEngineDependency
{
public IEnumerable<QueryDependencyDetail> GetDependencies()
{
var dependencies = new List<QueryDependencyDetail>
{
new QueryDependencyDetail<Tasks, long>
{
Order = 1,
Data = null // just to simplify
}
};
return dependencies;
}
}
If I call the method GetDependencies somewhere in the code how can I make the downcasting to access the generic type fields? I mean I will get the instances of QueryDependencyDetail type. Then is it possible to convert it to QueryDependencyDetail<TEntity, TKey>?
Or is there another way to do this?
EDIT
var testDep = new TestQueryDependency();
var dependencies = testDep.GetDependencies();
Remember that dependencies may have up to 20 different instances in my particular implementation.
How can I access the Data field, per example? (Just a simple scenario)
var first = dependencies.FirstOrDefault()?.Data; ?????
I will need this to perform dynamic queries using LINQ.
Thanks in advance.
I am not sure what you are trying to accomplish.
What if you put the generic arguments on the engine interface?
public interface IQueryEngineDependency<TEntity,TKey> where TEntity : BaseEntity<TKey> {
public IEnumerable<QueryDependencyDetail<TEntity,TKey>> GetDependencies();
}
Then you can create a test engine:
public class TestQueryDependency : IQueryEngineDependency<Tasks,long> {
public IEnumerable<QueryDependencyDetail<Tasks,long >> GetDependencies() {
var dependencies = new[] {
new QueryDependencyDetail<Tasks, long> {
Order = 1,
Data = null // just to simplify
}
};
return dependencies;
}
}
You should be able to just cast it, i.e. (QueryDependencyDetail<TEntity, TKey>) myObject
However, you must make sure that the type actually match the real object. Lets take a simplified example:
public class A { }
public class B<T> : A { }
public static B<T> Test<T>(A a) => (B<T>)a;
and
var a = new B<int>();
var b1 = Test<int>(a); // works since a is of type of B<int>
var b2 = Test<string>(a); // Will throw invalid cast exception since a is not of type B<string>
You can also test the type:
if(a is B<int> b)
The problem here is that you have to know the actual type of the object. You cannot just cast a to B<T> without somewhere declaring what T actually is.
The solution I have used for these kind of problems is to avoid anything that needs to know the generic type. Make sure the interface or base class contain all methods you ever need when interacting with the object. This can be a bit complicated when multiple classes are involved, but it is usually possible.
edit:
A third option could be to use reflection. This can allow you to inspect the actual types of the generic type parameters. It may allow for things like creating another object with the same generic type parameter. The downside is that using reflection can be quite cumbersome and may be error prone and slow.

How to understand this generic class defination with such type parameters constrain define in C# [duplicate]

Yesterday, I was explaining C#'s generic constraints to my friends. When demonstrating the where T : CLASSNAME constraint, I whipped up something like this:
public class UnusableClass<T> where T : UnusableClass<T>
{
public static int method(T input){
return 0;
}
}
And was really surprised to see it compile. After a bit of thinking, however, I figured it was perfectly legal from the point of view of the compiler - UnusableClass<T> is as much of a class as any other that can be used in this constraint.
However, that leaves a couple of questions: how can this class ever be used? Is it possible to
Instantiate it?
Inherit from it?
Call its static method int method?
And, if yes, how?
If any of these is possible, what would the type of T be?
This approach is widely used in Trees and other Graph-like structures. Here you say to compiler, that T has API of UnusableClass. That said, you can implement TreeNode as follows:
public class TreeNode<T>
where T:TreeNode<T>
{
public T This { get { return this as T;} }
public T Parent { get; set; }
public List<T> Childrens { get; set; }
public virtual void AddChild(T child)
{
Childrens.Add(child);
child.Parent = This;
}
public virtual void SetParent(T parent)
{
parent.Childrens.Add(This);
Parent = parent;
}
}
And then use it like this:
public class BinaryTree:TreeNode<BinaryTree>
{
}
Well.
public class Implementation : UnusableClass<Implementation>
{
}
is perfectly valid, and as such makes
var unusable = new UnusableClass<Implementation>();
and
UnusableClass<Implementation>.method(new Implementation());
valid.
So, yes, it can be instantiated by supplying an inheriting type as the type parameter, and similarly with the call to the static method. It's for instance useful for tree-like structures where you want to generically specify the type of children the node has, while it being the same type itself.
If any of these is possible, what would the type of T be?
They are all possible, and you are the one who is gonna determine what is the type of T.For example let's assume there is a type that inherits from UnusableClass<T>
class Foo : UnusableClass<Foo> { }
Now you can instantiate UnusableClass<Foo> because Foo satisfies the constraint:
UnusableClass<Foo> f = new UnusableClass<Foo>();
Then the type of T become Foo and if you try to call method you need to pass an instance of Foo.

c# generic type of own class [duplicate]

This question already has answers here:
C# variance problem: Assigning List<Derived> as List<Base>
(4 answers)
Closed 5 years ago.
So i'm having a problem with generic-types/inheritence in c#, this is the code
public class Tile{
...
public TileMap<Tile> tileMap{ get; set; }
...
}
public class TileMap<T> where T : Tile{
...
T newTile = (T)Activator.CreateInstance(typeof(T));
newTile.tileMap = this; //no compile
...
}
The compiler says: cannot convert TileMap<T> to TileMap<Tile>
I could make a generic type in Tile that I always give the same type as the tile itself, but this doesn't seem nice to me (and possible for mistakes).
I think i need some kind of generic type that automatically uses itself (the most sub-class)
(there are subclasses of Tile that should work in the TileMap)
This is kind of the idea that I want:
public class Tile<T> where T : this{
...
public TileMap<T> tileMap { get; set; }
...
}
But than without having to initialise the generic type, because it should always be the same as the class (and if i use a subclass of Tile, T should be the subclass).
Two approaches for you, OP.
1. The "right way" (using covariance)
It can be done using covariance, which is pretty hard to explain, but easy to show. Covariance requires that you use interfaces. This will compile and work:
public interface ITileMap<out T> where T : Tile
{
}
public class Tile
{
public ITileMap<Tile> tileMap { get; set; }
}
public class TileMap<T> : ITileMap<T> where T : Tile, new()
{
public TileMap()
{
T newTile = new T();
newTile.tileMap = this; //This compiles now!!!
}
public override string ToString()
{
return "Hello world!!!";
}
}
public class Program
{
public static void Main()
{
var t = new TileMap<Tile>();
Console.WriteLine(t);
}
}
Output:
Hello world!!!
Code available on DotNetFiddle
The key is this line:
public interface ITileMap<out T> where T : Tile
The out keyword tells c# that a ITileMap<base> class can refer to a ITileMap<derived> interface. With generics, you have to be explicit about this.
While regular inheritance allows you to assign base x = derived, c# does not allow TileMap<base> x = TileMap<derived>. Why? They don't inherit from each other. Instead, they both "inherit" (not really) from something else, a common ancestor, TileMap<>, which is their generic type definition. A type definition cannot be used as a type, so the way we deal with things like this in the generic world is with variance. In this specific case, you need covariance, e.g. the out keyword, which is only allowed in an interface.
2. The easy way
Covariance is pretty hard for a lot of people to get. You can avoid the whole issue, get rid of the interfaces, and skip the out keyword, simply by introducing an intermediary class, like this:
public class TileOnlyMap : TileMap<Tile>
Now your code will compile:
public class TileOnlyMap : TileMap<Tile>
{
public TileOnlyMap()
{
Tile newTile = new Tile();
newTile.tileMap = this;
}
}
In this example, we define a new class, TileOnlyMap, which doesn't take any generic parameters itself, but inherits from a TileMap<Tile> where the generic type parameter is determined at compile time. When you do this, the main thing you lose is early type binding. You can still use the TileOnlyMap to contain subclasses of Tile, only now they will be stored with runtime polymorphism instead of generic type compatibility and variance (the cost of this is negligible). Example:
public class SpecificTypeOfTile : Tile
{
}
public class TileOnlyMap : TileMap<Tile>
{
public TileOnlyMap()
{
var newTile = new Tile();
newTile.tileMap = this;
var newTile2 = new SpecificTypeOfTile(); //This works because of polymorphism
newTile2.tileMap = this;
}
}
See the full, second example on DotNetFiddle.
Personally, unless you have carefully planned your generic object model, I would stick with the far simpler second example. If you get your variance/interfaces/object model wrong, you will really create a serious mess!! On the other hand, if you understand co/contravariance and have planned out a generic object scheme, the first answer is the preferred approach. And I promise it will make much more sense the more you work with it.
If you can make an interface for TileMap, and it only uses T as a return, then you can utilize covariance:
public interface ITileMap<out T> where T : Tile
{
T DoSomething();
//this solution won't work if you need something like this:
//void DoSomethingElse(T tile);
}
Then modify the Tile property to take the interface instead:
public class Tile
{
public ITileMap<Tile> tileMap{ get; set; }
}
And then the implementation of TileMap:
public class TileMap<T> : ITileMap<T> where T : Tile
{
public T DoSomething()
{
T newTile = (T)Activator.CreateInstance(typeof(T));
newTile.tileMap = this;
return newTile;
}
}

It's possible pass subclass of superclass in <T>?

I have a class named GenericDao
internal class GenericDao<T> : IGenericDao<T> {
}
The two class of objects:
public class Empresa {
}
public class Assessoria : Empresa {
}
And i have one EmpresaDao:
public class EmpresaDao {
private GenericDao<Empresa> parent { get; set; }
public EmpresaDao() {
this.parent = new GenericDao<Empresa>();
}
}
How to instantiate the GenericDao using the subclass Assessoria? I do something like this, but not work:
public class EmpresaDao {
private GenericDao<Empresa> parent { get; set; }
public EmpresaDao(Type type) {
if (type == typeof(Assessoria)) {
this.parent = new GenericDao<Assessoria>();
} else {
this.parent = new GenericDao<Empresa>();
}
}
}
In short, you can't, really. However, you can cheat a little if you use a base interface that is not generic, or you use C# 4 and use a base interface that is generic, but with a covariant or contravariant (depending on need) type parameter. For the first case:
interface IGenericDaoBase {
}
interface IGenericDao<T> : IGenericDaoBase {
}
public class EmpresaDao {
private IGenericDaoBase parent { get; set; }
public EmpresaDao(Type type) {
// same as before
}
}
Admittedly, it might be better to rethink your design. Perhaps EmpresaDao can take a generic parameter itself, which would be used like so:
public class EmpresaDao<T> where T : Empresa {
private GenericDao<T> parent { get; set; }
public EmpresaDao() {
this.parent = new GenericDao<T>();
}
}
EDIT: In fact, the more I think about it, the more I believe this latter solution is the way to go. The type parameter in the constructor is fulfilling the same role as the type parameter on the class signature. So you won't have to change the calling code much, except to pass in a generic parameter instead of a Type object.
It is a good thing that your try don't work, you would introduce a bug if it did.
Suppose I have variables a, b both of type EmpresaDao. a is initilized with a Empresa parent and b is initialized with a Assessoria parent. Since a and b are of the same type, it should be possible to use one in place of the other everywhere. Suppose Assessoria but not Empresa has a method assess(). But you expect b.parent to be Assessoria so you want to call b.parent.assess() but you cannot call a.parent.assess() Which means a and b should not be of the same type in the first place.
The solution depends on whether you will ever call .parent.assess() :
a) If you will never call .parent.assess() within EmpresaDao class, let compile time type of the parent always be Empresa. Here is a solution :
public class EmpresaDao
{
private Empresa parent {get; set; }
public EmpresaDao(Func<Empresa> parentConstructor)
{
this.parent = parentConstructor();
}
}
static main()
{
var withEmpresaParent = new EmpresaDao(() => new Empresa());
var withAssessoriaParent = new EmpresaDao(() => new Assessoria());
..
}
b) You will sometimes call .parent.assess() within EmpresaDao class. Then you should make the EmpresaDao generic, as #siride said:
public class EmpresaDao<T> where T : Empresa
{
private T parent {get; set;}
}
However, it is still the case that you will have to make run time checks on parent before calling .parent.assess() Which means there is still something wrong in your design. But there is not enough information to decide what. Maybe .assess() method should be private and not to be called from outside (i.e. Assessoria should be a decorator on Empresa: subclass but with the same interface) Maybe "Empresa holding EmpresaDao" and "Assessoria holding EmpresaDao" should be two different classes. (implementing the same interface, probably)
Edit: Now I realize that, in my solution I mistakenly made the type of parent Empresa or Assessoria instead of GenericDao or GenericDao. I believe my main is still valid though.

c# - cast generic class to its base non-generic class

I have following classes:
public abstract class CustomerBase
{
public long CustomerNumber { get; set; }
public string Name { get; set; }
}
public abstract class CustomerWithChildern<T> : CustomerBase
where T: CustomerBase
{
public IList<T> Childern { get; private set; }
public CustomerWithChildern()
{
Childern = new List<T>();
}
}
public class SalesOffice : CustomerWithChildern<NationalNegotiation>
{
}
The SalesOffice is just one of few classes which represent different levels of customer hierarchy. Now I need to walk through this hierarchy from some point (CustomerBase). I can't figure out how to implement without using reflection. I'd like to implement something like:
public void WalkHierarchy(CustomerBase start)
{
Print(start.CustomerNumber);
if (start is CustomerWithChildern<>)
{
foreach(ch in start.Childern)
{
WalkHierarchy(ch);
}
}
}
Is there any chance I could get something like this working?
The solution based on suggested has-childern interface I implemented:
public interface ICustomerWithChildern
{
IEnumerable ChildernEnum { get; }
}
public abstract class CustomerWithChildern<T> : CustomerBase, ICustomerWithChildern
where T: CustomerBase
{
public IEnumerable ChildernEnum { get { return Childern; } }
public IList<T> Childern { get; private set; }
public CustomerWithChildern()
{
Childern = new List<T>();
}
}
public void WalkHierarchy(CustomerBase start)
{
var x = start.CustomerNumber;
var c = start as ICustomerWithChildern;
if (c != null)
{
foreach(var ch in c.ChildernEnum)
{
WalkHierarchy((CustomerBase)ch);
}
}
}
You could move the WalkHierarchy method to the base class and make it virtual. The base class implementation would only process the current node. For the CustomerWithChildern<T> class, the override would do an actual walk.
Try this:
if(start.GetType().GetGenericTypeDefinition() == typeof(CustomerWithChildern<>))
I believe that you want to make the lookup for the determination of doing to the walk an interface.
So maybe add an "IWalkable" interface that exposes the information needed to do the walk, then you can create your method checking to see if the passed object implements the interface.
"Is" and "As" only work on fully qualified generic types.
See this MSDN discussion for details including workarounds.
The most common workaround I've seen is to add an interface to the mix that your CustomerWithChildren could implement, and check for that interface.
I think everyone hits this "issue" when first working with generic classes.
Your first problem is hinted at in your question phrasing: an open generic type is NOT the base class to a closed one. There is no OO relationship here, at all. The real base class is CustomerBase. An "open" generic type is like a half-completed class; specifying type arguments "closes" it, making it complete.
While you can do:
Type t = typeof(CustomerWithChildern<>)
the condition
typeof(CustomerWithChildern<>).IsAssignableFrom(CustomerWithChildern<Foo>)
will always be False.
-Oisin
Explicitly with that method, no. However you can achieve the same functionality with an interface. In fact, you could just have your generic class implement IEnumerable. It's also worth noting that your class should also have "where T : CustomerBase" in order to ensure type safety.

Categories

Resources