This question already has answers here:
Collection of generic types
(10 answers)
Closed 7 years ago.
public abstract Column<T>
{
private T Value {get;set;}
public abstract string Format();
}
public class DateColumn : Column<DateTime>
{
public override string Format()
{
return Value.ToString("dd-MMM-yyyy");
}
}
public class NumberColumn : Column<decimal>
{
public override string Format()
{
return Value.ToString();
}
}
The problem I have is adding these into a generic collection. I know its possible but how can I store multiple types in a collection etc
IList<Column<?>> columns = new List<Column<?>()
I would really appreciate any advice on achieving this goal. The goal being having different column types stored in the same List. Its worth mentioning I am using NHibernate and the discriminator to load the appropriate object.Ultimately the Value needs to have the type of the class.
Many thanks for your help in advance.
In order to be stored in a List<T> together the columns must have a common base type. The closest common base class of DateColumn and NumberColumn is object. Neither derives from Column<T> but instead a specific and different instantiation of Column<T>.
One solution here is to introduce a non-generic Column type which Column<T> derives from and store that in the List
public abstract class Column {
public abstract object ValueUntyped { get; }
}
public abstract class Column<T> : Column {
public T Value { get; set; }
public override object ValueUntyped { get { return Value; } }
}
...
IList<Column> list = new List<Column>();
list.Add(new DateColumn());
list.Add(new NumberColumn());
Generics are all about specifying type. If you want to use dynamic types, use classic ArrayList instead.
It probably makes sense to derive from a non-generic Column class that wraps up as much of the non-generic common interface of a column... then to declare your list as List<Column>.
Related
I have the following abstract class AggregateId<T> class now, but the type of the Value property there used to be a Guid. I changed it because I needed it to be a lot more generic, the problem is if I change the class in order to add a new Generic type, like AggregateId<T, TValue> it would make me perform a lot of refactoring, and I gonna end adding a lot of "noise" in the code.
The solution for this problem was change the AggregateId.Value to object type and them
using the new modifier with a different type for the classes that inherit from it.
public abstract class AggregateId<T> where T : IAggregateRoot
{
public object Value { get; }
protected AggregateId(object value)
{
Value = value;
}
}
public class SomeClassId : AggregateId<SomeClass>
{
public new string Value { get; }
public MarketId(string value)
: base(value)
{
Value = value;
}
}
Now, I tried to find some information about if it is OK or why would be bad, do what I have done, but I found nothing anywhere, so my question is if there is any problem to make it the way I did?
TLDR: Is there anyway to override an abstract property and change it's return type at the same time, just like you can do with concrete properties? I know the direct answer is "no", but I'm wondering if there's any workaround that doesn't involve adding a second property.
Let's say I have this abstract class:
public abstract class Item {
public abstract string SerialNumber { get; }
public string PartNumber => "34";
}
Let's say I want a Toy class that implements Item. Let's also say for some reason I want the SerialNumber and PartNumber properties to both be int values in the child class even though they are strings on the base. See below:
public abstract class Toy {
public override int SerialNumber => 5; //Doesn't compile obviously
public new int PartNumber => int.ParseInt(base.PartNumber); //works fine, refines the type but keeps the value
}
I included PartNumber just to show that I understand how the new keyword is supposed to work. That part works fine for me.
My question is: Is there any way to both override AND refine the type of SerialNumber at the same time? I understand what I have above doesn't work, but I'm looking for a simple workaround. The goal is to NOT use an extra property (like SerialNumberInt or something) so that the Toy class's methods can refer to SerialNumber and get it as an int.
Thanks!
This can be done using Generics. But before you do it you need to be sure you are approaching your problem correctly. That said, I've used the below idea to map domain entities with common properties but they have different Types for their entity id.
public abstract class ItemBase<TId>
{
protected ItemBase(TId id)
{
ItemId = id;
}
public TId ItemId { get; }
}
public class Toy : ItemBase<int>
{
public Toy(int id) : base(id)
{
}
}
public class NotAToy : ItemBase<Guid>
{
public NotAToy(Guid id) : base(id)
{
}
}
You can do that using generics (see below) or you could just make everything an object. However, this really doesn't feel like a great solution but I don't know the purpose behind arbitrarily changing the types in this case.
public abstract class Item <T,V>
{
public abstract T SerialNumber { get; }
public V PartNumber { get; }
}
public abstract class Toy : Item<int, int>
{
public override int SerialNumber => 5;
public new int PartNumber => int.Parse(base.PartNumber.ToString());
}
public abstract class ToyString : Item<string, string>
{
public override string SerialNumber => "3";
public new string PartNumber => "34";
}
You can use generics to achieve this as follows:
public abstract class Item<T> {
public abstract T SerialNumber { get; }
}
public class Toy : Item<int> {
public override int SerialNumber => 5;
}
However, you shouldn't necessarily do this. You may want to confirm if this design is appropriate in your case since if you are redefining types on derived classes then it's most likely a problem with how you are defining your base class.
What you're trying to do is not possible.
The reason for this is that your base class expresses a contract, part of which is the return type of methods it exposes.
Your subclass cannot fulfill this contract: suppose you have a class "ItemSubmitter", which has a method "submitItem", which internally does:
string partNumberToSubmit = item.PartNumber;
Since item.PartNumber in your example returns an int, this would cause an exception. How would you expect the compiler to deal with this situation?
So, it is not possible. This concept is generalized as the Liskov Substitution Principle from Barbara Liskov, see e.g. https://en.wikipedia.org/wiki/Liskov_substitution_principle.
You could use generics, but this would require all base class consumers to also be generic. In this case I'd question if you need a base class at all and simply make the consumers generic.
See also C# Override abstract property with concrete property
It appears you've answered your own question (stated differently) some time ago: https://stackoverflow.com/a/40657803/11389043
I'm trying to construct a class in c# (5.0) that I can use as a base class and it contains a List, but List could be 2 different types. I want to do the following:
public class BaseC
{
string header { get; set; }
List<object> recs { get; set; }
}
public class derive1: BaseC
{
List<myclassA> recs;
}
public class derive2: BaseC
{
List<myclassB> recs;
}
and importantly what I want to do is return the derived classes from a method in another class:
public BaseC PopulateMyDerivedClass()
{
BaseC b = new BaseC();
b.header = "stuff";
b.recs = FileHelperEngine<myclassB> fhe.ReadStringAsList(x);
}
the main point is that method PopulateMyDerivedClass really does the exact same thing for both derive1 and derive2, just that it returns a different type of list.
I think I need generics. But is that at the base class level and also is PopulateMyDerivedClass then supposed to return a generic? I think that perhaps I am not dealing with polymorhpism, but as you can guess I am new to generics, so struggling.
I think what you want is to make BaseC a generic class and specify the generic when defining the derived classes:
public class BaseC<T>
{
//...
virtual List<T> Recs { get; set; }
}
public class Derived1 : Base<MyClassA>
{
override List<MyClassA> Recs { get; set; }
}
Good point by Alexei Levenkov:
Usual note: DerivedX classes in this case will not have common parent unlike original sample. One may need to add more layer of classes (as non-generic parent of BaseC) or use an interface if DerivedX need to be treated as having common parent/interface.
I get the feeling that your code design could use some rethinking. For one, typically when we talk about "polymorphism", we are usually talking about polymorphic behaviors (methods), rather than members. I think you might want to consider two classes that implement an interface that does all the things you want each class to do (parses data into its own type of list and acts on it as you need it to).
Nevertheless, without getting way into the details of your code, I think something like this might be what you were trying to achieve:
public class BaseC<T>
{
string header { get; set; }
public List<T> recs {get;set;}
}
and
public BaseC<T> PopulateClass<T>()
{
var b = new BaseC<T>();
b.recs = new List<T>();
T first = (T)Convert.ChangeType("1", typeof(T));
b.recs.Add(first);
return b;
}
And to check our sanity:
BaseC<String> d1 = PopulateClass<String>();
System.Diagnostics.Debug.Print(d1.recs.First().ToString());
System.Diagnostics.Debug.Print(d1.recs.First().GetType().ToString());
BaseC<int> d2 = PopulateClass<int>();
System.Diagnostics.Debug.Print(d2.recs.First().ToString());
System.Diagnostics.Debug.Print(d2.recs.First().GetType().ToString());
prints
1
System.String
1
System.Int32
I am trying to find the right way to use a Generic List of Generic Interfaces as a variable.
Here is an example. It is probably not the best, but hopefully you will get the point:
public interface IPrimitive<T>
{
T Value { get; }
}
and then in another class, I want to be able to declare a variable that holds a list of objects that implement IPrimitive<T> for arbitrary T.
// I know this line will not compile because I do not define T
List<IPrimitive<T>> primitives = new List<IPrimitives<T>>;
primitives.Add(new Star()); // Assuming Star implements IPrimitive<X>
primitives.Add(new Sun()); // Assuming Sun implements IPrimitive<Y>
Note that the T in IPrimitive<T> could be different for each entry in the list.
Any ideas on how I could setup such a relationship? Alternative Approaches?
public interface IPrimitive
{
}
public interface IPrimitive<T> : IPrimitive
{
T Value { get; }
}
public class Star : IPrimitive<T> //must declare T here
{
}
Then you should be able to have
List<IPrimitive> primitives = new List<IPrimitive>;
primitives.Add(new Star()); // Assuming Star implements IPrimitive
primitives.Add(new Sun()); // Assuming Sun implements IPrimitive
John is correct.
Might I also suggest (if you are using C# 4) that you make your interface covariant?
public interface IPrimitive<out T>
{
T Value { get; }
}
This could save you some trouble later when you need to get things out of the list.
You say it won't work because you don't define T. So define it:
public class Holder<T>
{
public List<IPrimitive<T>> Primitives {get;set;}
}
This is one of the most complicated elements of the c# language though it is incredibly important for building well defined components. As such, c# falls short. However it is definitely possible to make this work.
The trick is to have 3 parts:
A non generic interface that contains all requirements of the interface.
A generic abstract class that implements the non generic interface and performs the type conversions as necessary.
A class that implements the generic abstract class with the appropriately typed results
For example:
public interface INonGenericInterface{
void Execute(object input);
object GetModel();
}
public abstract class IGenericInterfaceBase<T> : INonGenericInterface{
void INonGenericInterface.Execute(object input){
Execute((T) input);
}
object INonGenericInterface.GetModel(){
return GetModel();
}
protected abstract void Execute(T input);
protected abstract T GetModel();
}
public class ImplementingClass : IGenericInterfaceBase<ModelClass>{
protected override void Execute(ModelClass input){ /*Do something with the input */ }
protected override ModelClass GetModel(){ return new ModelClass();}
}
//Extras for demo
public class ModelClass { }
public class ModelClass2 { }
public class ImplementingClass2 : IGenericInterfaceBase<ModelClass2>
{
protected override void Execute(ModelClass2 input) { /*Do something with the input */ }
protected override ModelClass2 GetModel() { return new ModelClass2(); }
}
var agi = new INonGenericInterface[] { new ImplementingClass(), new ImplementingClass2() };
agi[0].Execute(); var model = agi[0].GetModel();
agi[1].Execute(); var model2 = agi[1].GetModel();
//Check the types of the model and model2 objects to see that they are appropriately typed.
This structure is incredibly useful when coordinating classes w/ one another because you're able to indicate that an implementing class will make use of multiple classes and have type checking validate that each class follows established type expectations. In addition, you might consider using an actual class instead of object for the non-generic class so that you can execute functions on the result of the various non-generic calls. Using this same design you can have those classes be generic classes w/ their own implementations and thus create incredibly complex applications.
To OP: Please consider changing the accepted answer to this to raise awareness of the correct approach as all previously stated answers fall short for various reasons and have probably left readers with more questions. This should handle all future questions related to generic classes in a collection.
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.