This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do I create a list of objects that inherit from the same generic class with varying types?
I'm using several objects where they are inherited from an abstract class. But to use the abstract class must be declara a generic datatype.
I'm having problems because I need to have a list where contains a list of ProblemBase, although each one contains a different TResult datatype.
public abstract class ProblemBase<TResult>
{
TResult[] Array;
}
And I want to get Array property. That's the problem.
This type of thing happens for me quite often. The solution I typically go with is to have a base class for ProblemBase<T> that is type free:
public abstract class ProblemBase
{
public abstract object Result { get; }
}
public abstract class ProblemBase<TResult> : ProblemBase
{
public override object Result
{
get { return Result; }
}
new public TResult Result { get; private set; }
}
Whenever you need a collection of problems, then, you can make a collection of ProblemBase without the generics.
If TResult has its own required inheritance hierarchy, then you can do this instead:
public abstract class ProblemBase
{
public abstract ResultBase Result { get; }
}
public abstract class ProblemBase<TResult> : ProblemBase
where TResult : ResultBase
{
public override ResultBase Result { get { return Result; } }
new public TResult Result { get; private set; }
}
Related
This question already has answers here:
Why an inherited interface can't be converted to its base interface in generic context?
(2 answers)
Closed 2 years ago.
I'm trying to write a generic function like the example of the image below.
The idea is to have a method that will receive a generic type that must inherit an abstract class that has a generic configuration which has another abstract class.
public class MainCode
{
public MainCode()
{
Execute<DefaultOptions>();
}
public void Execute<T>() where T : BaseClassOptions<BaseClassConfiguration> { }
}
public class DefaultOptions : BaseClassOptions<DefaultConfiguration> { }
public abstract class BaseClassOptions<T> where T : BaseClassConfiguration
{
public T Config { get; set; }
}
public class DefaultConfiguration : BaseClassConfiguration { }
public abstract class BaseClassConfiguration
{
public string Host { get; set; }
}
But I got the following error:
Could you please help me?
Maybe this will work for you?
public MainCode()
{
Execute<DefaultOptions, DefaultConfiguration>();
}
public void Execute<T, T2>() where T : BaseClassOptions<T2> where T2: BaseClassConfiguration
{ }
The problem is that BaseClassOptions<BaseClassConfiguration> is not the base class for the DefaultOptions, that's why you get this error. It happens because type parameters on generic classes are neither covariant nor contravariant, i.e. there is no inheritance relationship between specializations of the same generic class. If you don't want to use interfaces it may worth to say compiler directly what class to use as a generic parameter with your base type.
This is class design question.
I have main abstract class
public abstract class AbstractBlockRule
{
public long Id{get;set;}
public abstract List<IRestriction> Restrictions {get;};
}
public interface IRestriction{}
public interface IRestriction<T>:IRestriction where T:struct
{
T Limit {get;}
}
public TimeRestriction:IRestriction<TimeSpan>
{
public TimeSpan Limit{get;set;}
}
public AgeRestriction:IRestriction<int>
{
public int Limit{get;set;}
}
public class BlockRule:AbstractBlockRule
{
public virtual List<IRestriction> Restrictions {get;set;}
}
BlockRule rule=new BlockRule();
TimeRestriction t=new TimeRestriction();
AgeRestriction a=new AgeRestriction();
rule.Restrictions.Add(t);
rule.Restrictions.Add(a);
I have to use non-generic Interface IRestriction just to avoid specifying generic type T in main abstract class. I'm very new to generics. Can some one let me know how to better design this thing?
Your approach is typical (for example, IEnumerable<T> implements IEnumerable like this). If you want to provide maximum utility to consumers of your code, it would be nice to provide a non-generic accessor on the non-generic interface, then hide it in the generic implementation. For example:
public abstract class AbstractBlockRule
{
public long Id{get;set;}
public abstract List<IRestriction> Restrictions { get; set; }
}
public interface IRestriction
{
object Limit { get; }
}
public interface IRestriction<T> : IRestriction
where T:struct
{
// hide IRestriction.Limit
new T Limit {get;}
}
public abstract class RestrictionBase<T> : IRestriction<T>
where T:struct
{
// explicit implementation
object IRestriction.Limit
{
get { return Limit; }
}
// override when required
public virtual T Limit { get; set; }
}
public class TimeRestriction : RestrictionBase<TimeSpan>
{
}
public class AgeRestriction : RestrictionBase<TimeSpan>
{
}
public class BlockRule : AbstractBlockRule
{
public override List<IRestriction> Restrictions { get; set; }
}
I also showed using a base restriction class here, but it is not required.
The runtime treats IRestriction<TimeSpan> and IRestriction<int> as different distinct classes (they even have their own set of static variables). In your case the only classes common to both IRestriction<TimeSpan> and IRestriction<int> in the inheritance hierarchy are IRestriction and object.
So indeed, having a list of IRestriction is the only sensible way to go.
As a side note: you have a property Limit in there that you might want to access regardless of whether you're dealing with an IRestriction<TimeSpan> or IRestriction<int>. What I would do in this case is to define another property object Limit { get; } on IRestriction, and hide it in the actual implementation. Like this:
public interface IRestriction
{
object Limit { get; }
}
public interface IRestriction<T> : IRestriction
where T : struct
{
new T Limit { get; set; }
}
public class TimeRestriction : IRestriction<TimeSpan>
{
public TimeSpan Limit { get; set; }
// Explicit interface member:
// This is hidden from IntelliSense
// unless you cast to IRestriction.
object IRestriction.Limit
{
get
{
// Note: boxing happens here.
return (object)Limit;
}
}
}
This way you can access Limit as object on all your IRestriction when you don't care what type it is. For example:
foreach(IRestriction restriction in this.Restrictions)
{
Console.WriteLine(restriction.Limit);
}
Interfaces are contracts that need to be followed by the entity that implements the contract.
You have created two contract with the same name IRestriction
As far as I can see, what you are basically may need is a flag for classes that can be restricted, which should implement the IRestriction non-generic interface.
The second interface seems to be restrictable objects that also contain a limit property.
Hence the definition of the second IRestriction interface can be ILimitRestriction or whatever name suits your business needs.
Hence ILimitRestriction can inherit from IRestriction which would mark classes inheriting ILimitRestriction still objects of IRestriction
public abstract class AbstractBlockRule
{
public long Id{get;set;}
public abstract List<IRestriction> Restrictions {get;};
}
public interface IRestriction{}
public interface IRestrictionWithLimit<T>:IRestriction where T:struct
{
T Limit {get;}
}
public TimeRestriction:IRestrictionWithLimit<TimeSpan>
{
public TimeSpan Limit{get;set;}
}
public AgeRestriction:IRestrictionWithLimit<int>
{
public int Limit{get;set;}
}
public class BlockRule:AbstractBlockRule
{
public virtual List<IRestriction> Restrictions {get;set;}
}
This question already has answers here:
Convert List<DerivedClass> to List<BaseClass>
(13 answers)
Closed 5 years ago.
Let's consider that there is an abstract base class and one, or more child classes:
public abstract class BaseInnerClass
{
public int Id { get; set; }
}
public class ConcreteInnerClass : BaseInnerClass
{
public string Name { get; set; }
}
Then, let's assume there is a generic abstract class that has a property of above abstract class type:
public abstract class GeneriAbstractTestClass<T> where T : BaseInnerClass
{
public T InnerClass { get; set; }
}
Then let's make a class that inherits from the class above:
public class ConcreteTestClass : GeneriAbstractTestClass<ConcreteInnerClass>
{
public string ConcreteString { get; set; }
}
So now everything is prepared to ask a question ;) Why it is not possible to do it:
//cannot convert initializer type
GeneriAbstractTestClass<BaseInnerClass> genericClass = new ConcreteTestClass();
while this is allowed:
//ok
BaseInnerClass baseInner = new ConcreteInnerClass();
What's the difference between this two assignments?
This has nothing to do with abstract classes. A simpler example would be
List<BaseInnerClass> base = new List<ConcreteInnerClass>
The fact that type A is derived from type B does not imply that type C<A> is derived from type C<B>. Your example is a little bit more complicated, but it can be explained using the same logic.
Note that you can define another concrete type:
public class EvilConcreteInnerClass : BaseInnerClass
{
}
If what you wanted was possible, then the following would work:
GeneriAbstractTestClass<BaseInnerClass> genericClass = new ConcreteTestClass();
genericClass.InnerClass = new EvilConcreteInnerClass(); // OK, because the compiler sees `T` as `BaseInnerClass`
genericClass variable points to an object whose T generic parameter is ConcreteInnerClass, so assigning EvilConcreteInnerClass to the property would result in a run-time exception.
Actually. You can do this. But you need to specify interface with covariant out T generic, because it is type safe to make those casts.
Example
namespace ConsoleTest
{
class Program
{
static void Main(string[] args)
{
var a = new Generic<Concrete>();
IGeneric<Base> c = new Generic<Base>();
c = a;
}
}
public interface IGeneric<out T> where T: Base
{
T Inner { get; }
}
public class Generic<T> : IGeneric<T>
where T : Base
{
public T Inner { get; set; }
}
public class Concrete : Base
{
}
public class Base
{
}
}
Delegates also not restricted if they specify covariant out generic templates.
It means those casts you want is OK as long as you use readonly generic properties. So, like #Kapol said and provided you example why it is not type safe to allow setters on properties or pass T into function.
Summary
Use ReadOnly interfaces if you want to use those kinds of casts.
So I have been working with the Neo4jClient library for C# and I am fairly new to both worlds.
I have this POCO here:
public class SetEntity
{
public string GUID { get; set; }
public string Name { get; set; }
public string Type { get; set; }
public string CreatedDate { get; set; }
}
This object class is used in various methods, one in particular for creating a relationship between two nodes however I have to explicitly say which POCO is used to create it IRelationshipAllowingSourceNode<SetEntity> and IRelationshipAllowingTargetNode<EntityInstance>. Below is the entire class that handles that.
class GraphRelationshipEntityInstanceToSetEntity : Relationship, IRelationshipAllowingSourceNode<EntityInstance>, IRelationshipAllowingTargetNode<SetEntity>
{
string RelationshipName;
public GraphRelationshipEntityInstanceToSetEntity(NodeReference targetNode)
: base(targetNode)
{
}
public GraphRelationshipEntityInstanceToSetEntity(string RelationshipName, NodeReference targetNode)
: base(targetNode)
{
this.RelationshipName = RelationshipName;
}
public override string RelationshipTypeKey
{
get { return RelationshipName; }
}
}
Is there a way that I can pass <SetEntity> or any other objects into IRelationshipAllowingSourceNode<Object>. I see it as unnecessary to create this class for every node type that will have a relationship with another node type.
I'm not familiar with the Neo4jclient but can comment on generics in c#.
In c# you can define an interface with which is said to have an open generic type. That is, the neo4jclient presumably declares an interface IRelationshipAllowingSourceNode<T> with some method on which presumably use an instance of T/returns T.
This is said to be an interface with an open generic type.
When you implement that interface you have close the open generic type by specifying the exact type you're working with. You can however, make your class use two open generic types as follows, and then close the generic types when you instantiate GraphRelationshipEntityInstanceToSetEntity. See below.
class GraphRelationshipEntityInstanceToSetEntity<T, T1> : Relationship, IRelationshipAllowingSourceNode<T>, IRelationshipAllowingTargetNode<T1>
{
string RelationshipName;
public GraphRelationshipEntityInstanceToSetEntity(NodeReference targetNode)
: base(targetNode)
{
}
public GraphRelationshipEntityInstanceToSetEntity(string RelationshipName, NodeReference targetNode)
: base(targetNode)
{
this.RelationshipName = RelationshipName;
}
public override string RelationshipTypeKey
{
get { return RelationshipName; }
}
}
See here for another question which has been answered on generics:
Generics -Open and closed constructed Types
Hope that this helps.
Tim
i have a litte problem and i need some help :)
For example i have a simle abstract class
public abstract class BaseDefinition
{
public int Id { get;set; }
public string Name { get;set; }
}
and other base class
public abstract class BaseParentClass
{
public string Name { get;set; }
public string Schema { get;set; }
}
and first generic abstract class
public abstrac class BaseParentClass<T> :
BaseParentClass where T : BaseDefinition
{
public IList<T> Objects {get;set;}
}
and first implementations
public class ClassADefintion : BaseDefinition
{
public bool IsChanged {get;set;}
}
public class ClassAObject : BaseParentClass<ClassADefinition>
{
public bool OtherField {get;set;}
}
public class ClassBDefintion : BaseDefinition
{
public bool IsBBBChanged {get;set;}
}
public class ClassBObject : BaseParentClass<ClassBDefinition>
{
public bool OtherBBBBField {get;set;}
}
Sorry for class name, but I can't create anything better (it's only example)
As We see, now is all OK :).
I have some methods who returns a IEnumerable of generic implementation
IEnumerable<ClassBObject> ClassBObjectCollection;
IEnumerable<ClassAObject> ClassAObjectCollection;
Now i must create a method, who can take a generic objects in IEnumerable
public void DoWork(IEnumerable<BaseParentClass<BaseDefinition>> objects)
{
foreach(var baseObj in objects)
{
foreach(var baseDef in baseObj.Objects)
{
// do some work
}
}
}
How i remember BaseObject<BaseDefinition> != ClassAObject, but compiler doesn't put on screen any errors. I remember in .NET in generic interface We can use IN and OUT T, so i try make this
public interface IBaseParentClass<out T> where T : BaseDefinition
{
IList<T> Objects {get;set;}
}
Yup, You can't make a List of <out T>. Somebody have any idea for this problem ?
I can get this fields values by reflection, but i have abstract class and interface so i think is a better way.
I don't have a compiler at hand, but I think it should be possible to rewrite DoWork as such:
public void DoWork<T>(IEnumerable<BaseObject<T>> objects)
where T : BaseDefinition
{
foreach(var baseObj in objects)
{
foreach(var baseDef in baseObj.Objects)
{
// do some work
}
}
}
I am not sure whether the compiler will be able to infer T for you, try it out.
Another possibility may be that if you enumerate those objects anyway, to make Objects of Type IEnumerable(Of T).