Class with generic property MUST be generic? - c#

Let's say I have this class
public class Foo<T>
{
public List<T> FooList { get; set;}
}
And this class is used by another class like:
public class Bar
{
public List<Foo> Foos { get; set; } // THIS DOESNT COMPILE
}
The above solution doesn't work because it says my generic type Foo requires 1 type argument.
In my real scenario, I don't think it makes much sense to propagate the generic to Bar class, like:
public class Bar<T>
{
public List<Foo<T>> Foos { get; set; } // Not the solution I want
}
So I would like to know: which is the best solution here, if any? Do I really need to make my Bar class generic? In Java, if Im not mistaken, I could do something like List<Foo<?>> Foos and it would work...
Edit
So, as asked, I'm giving the concrete example.
I am doing some DTO classes for Highcharts.
Highcharts, among a lot of other objects, has the series object. This series object have the data property which can be pretty much anything: A list of numbers, a list of pairs of numbers, etc, etc.
So my generic class would be the series:
public class SeriesDto<T>
{
public List<T> Data { get; set; }
// Other options ...
}
And it would be used by the HighchartsDto class:
public class HighchartsDto {
// Lot of things..
// ...
public List<SeriesDto> Series { get; set; } // doesn't compile
}
It doesn't make sense to make HighchartsDto generic because the same chart can have different types of series.

You can add an interface:
public interface IFoo
{
}
public class Foo<T> : IFoo
{
public List<T> FooList { get; set; }
}
public class Bar
{
public List<IFoo> Foos { get; set; }
}

The trouble is you haven't given a realistic example, just a hypothetical.
The following doesn't compile, because it doesn't knows what generic type you want to use? what should it guess?
public class Bar
{
public List<Foo> Foos { get; set; } // THIS DOESNT COMPILE
}
If you understand Bar, then you could do something lie this and mark the type in advance, i.e Bar will always implement Foo<int>
public class Bar
{
public List<Foo<int>> Foos { get; set; }
}
If you want more power, and to choose the type at a later point in code, you can do this
public class Bar<T>
{
public List<Foo<T>> Foos { get; set; }
}
Or as Backs pointed out you can add an interface, all this is really doing though is hiding the members of Foo<T>, List<T> FooList { get; set;} is unusable in this context.
You need to work out what want, and why you want it, and maybe better explain it

"This series object have the data property which can be pretty much anything: A list of numbers, a list of pairs of numbers, etc, etc."
A List<T> is not a good for a collection that can be anything. A List<T> is a collection of one thing of type T. Maybe you want the good old ArrayList which is a collection of object, and thus it can be anything. In essence you have to decide which is a common type the contents can have.
Contents have nothing in common, other than deriving from object
public class SeriesDto
{
public ArrayList Data { get; set; }
// Other options ...
}
public class HighchartsDto
{
// Lot of things..
// ...
public List<SeriesDto> Series { get; set; } // doesn't compile
}
class Program
{
static void Main(string[] args)
{
var dto = new SeriesDto();
dto.Data.Add("A string");
dto.Data.Add(1001);
dto.Data.Add(new TimeSpan(0, 0, 15));
var list = new HighchartsDto();
list.Series.Add(dto);
TimeSpan time = (TimeSpan)list.Series[0].Data[2]; // 15 seconds
}
}
Contents have a basic interface in common which includes all properties and methods that is shared with all types
public interface ISeriesData
{
DateTime CreatedTime { get; }
}
public class StringData : ISeriesData
{
public StringData(string name)
{
this.Name = name;
this.CreatedTime = DateTime.Now;
}
public string Name { get; }
public DateTime CreatedTime { get; }
}
public class IntegerData : ISeriesData
{
public IntegerData(int value)
{
this.Value = value;
this.CreatedTime = DateTime.Now;
}
public DateTime CreatedTime { get; }
public int Value { get; }
}
public class SeriesDto
{
public List<ISeriesData> Data { get; set; }
// Other options ...
}
public class HighchartsDto
{
// Lot of things..
// ...
public List<SeriesDto> Series { get; set; } // doesn't compile
}
class Program
{
static void Main(string[] args)
{
var a = new StringData("A");
var b = new IntegerData(1001);
var dto = new SeriesDto();
dto.Data.Add(a);
dto.Data.Add(b);
var list = new HighchartsDto();
list.Series.Add(dto);
DateTime time = list.Series[0].Data[0].CreatedTime; // time
}
}
Make HighChartsDto Generic and inherit from it the concrete classes.
public class SeriesDto<T>
{
public List<T> Data { get; set; }
// Other options ...
}
public class HighChartsDto<L, T> where L : SeriesDto<T>
{
// Lot of things..
// ...
public int SomethingElse { get; set; }
public List<L> Series { get; set; } // doesn't compile
}
public class HighChartsStringDto : HighChartsDto< SeriesDto<string>, string>
{
}
class Program
{
static void Main(string[] args)
{
var a = new SeriesDto<string>();
a.Data.Add("A");
a.Data.Add("B");
a.Data.Add("C");
var b = new SeriesDto<string>();
b.Data.Add("1");
b.Data.Add("2");
b.Data.Add("3");
var list = new HighChartsStringDto();
list.Series.Add(a);
list.Series.Add(b);
string x = list.Series[1].Data[2]; // "C"
}
}

Althoug I'm aware that this solution is flawed, this would be another way to do this.
public class Foo<T> : Foo
{
public List<T> FooList { get; set; }
}
public class Foo
{
}
So you're creating a non-generic class from which your generic Foo derives.
Then you can do this:
public class Bar
{
public List<Foo> Foos { get; set; } // THIS DOES NOW COMPILE
}
And then if needed you could cast the non-generic List to a list of your generic-type like this:
bar.Foos.Cast<Foo<GENERICTYPE>>()
But that requires you knowing which exact type it is going to be.

Related

Generics: cast derived class back to it's parent super class

I have three base classes:
public class ItemBase
{
public string Name { get; set; }
}
public class ProductBase<T> : ItemBase
where T : ItemBase
{
public List<T> Modifiers { get; set; }
public List<T> GroupModifiers { get; set; }
}
public class ModifierBase<T> : ItemBase
where T : ItemBase
{
public List<T> ChildModifiers { get; set; }
}
And two derived classes:
public class Product : ProductBase<Modifier>
{
public string Some_Product_Specific_Property { get; set; }
}
public class Modifier : ModifierBase<Modifier>
{
public string Some_Modifier_Specific_Property { get; set; }
}
The intent behind all this is to have different sets of derived classes like Product and ProductFromOtherSystem each with it's own specific properties but with the same basic properties.
And now I need to process basic properties of any class derived from ProductBase<T>.
For this purpose I want to use something like this:
public static void DoSomething(ProductBase<ModifierBase<ItemBase>> item)
{
Console.WriteLine(item.Name);
}
The issue here is that I cannot pass parameters to it:
Product product1 = new Product();
DoSomething(product1);
ProductFromOtherSystem product2 = new ProductFromOtherSystem();
DoSomething(product2 as ProductBase<ModifierBase<ItemBase>>);
The error is like
Cannot convert type _ to _ via a reference conversion, boxing conversion, unboxing conversion, wrapping conversion, or null type conversion
I've tried to downcast it somehow but have not found any solution. I wonder if it is possible to do it?

How would one handle different return types when overriding abstract method

Say I have the following classes:
public abstract class A
{
protected abstract ReturnA Foo();
public void UseFoo()
{
var foo = Foo();
if (foo != null)
{
//logic here
}
}
}
public class B : A
{
protected override ReturnA Foo()
{
// Implementation specific code that returns ReturnB instead.
}
}
public class C : A
{
protected override ReturnA Foo()
{
// Implementation specific code that returns ReturnC instead.
}
}
public class ReturnA
{
public int Id { get; set; }
public string Address { get; set; }
}
public class ReturnB
{
public string Id { get; set; }
public string PhoneNumber { get; set; }
}
public class ReturnC
{
public Guid Id { get; set; }
public string Name { get; set; }
}
I know that C# does not support derived return types, but this is not what I need either.
Classes B and C are implementation specific and therefore their return types have nothing to do with eachother.
The reason why I would want to handle this, is because the method UseFoo in class A may have some generic checks and other generic logic, that has nothing to do with the returned object itself.
So I want to "outsource" only the code that is implementation specific and not have to instead make UseFoo abstract and have every implementation write the same generic code.
Is there any way to solve this at all?
EDIT: Neither ReturnC nor ReturnB are derived from ReturnA. Updated with examples.

C# Counting properties of Class with child/nested objects

I have the following construction of classes, here simplified as child classes of a 'mother' class called DataClass, which also contains one simple method:
public class DataClass
{
public int num { get; set; }
public string code { get; set; }
public PartClass part { get; set; }
public MemberClass member { get; set; }
public int Count()
{
Type t = typeof(DataClass);
return typeof(DataClass).GetProperties().Length;
}
}
public class PartClass
{
public int seriesNum { get; set; }
public string seriesCode { get; set; }
}
public class MemberClass
{
public int versionNum { get; set; }
public SideClass side { get; set; }
}
public class SideClass
{
public string firstDetail { get; set; }
public string secondDetail { get; set; }
public bool include { get; set; }
}
The issue is, I want to refactor the method so that it can give me an accurate counting of all properties found, including the ones in nested or child classes. In the above example, it only counts properties of DataClass, while I wanted it to return 2 for DataClass + 2 for PartClass + 1 for MemberClass + 3 for SideClass, sums up to 8 properties you may set through DataClass.
Can someone help me with this?
You can introduce interface with Count() method
public interface ICountable
{
int Count();
}
And use this interface to mark all types, which properties are participating in Count() calculation.
You can see the generic abstract class to implement this interface below. Generic T parameter is type whose properties need to be calculated. You implement a calculation logic only once and inherit this class where needed. You also go through all of properties, implementing ICountable, to calculate them as well (some kind of recursion)
public abstract class Countable<T> : ICountable
{
public int Count()
{
Type t = typeof(T);
var properties = t.GetProperties();
var countable = properties.Select(p => p.PropertyType).Where(p => typeof(ICountable).IsAssignableFrom(p));
var sum = countable.Sum(c => c.GetProperties().Length);
return properties.Length + sum;
}
}
and inherit it in your classes
public class DataClass : Countable<DataClass>
{
...
}
public class PartClass : Countable<PartClass>
{
...
}
public class MemberClass : Countable<MemberClass>
{
...
}
public class SideClass : Countable<SideClass>
{
...
}
And this is for the test
var dataClass = new DataClass();
var count = dataClass.Count();
It returns 8 as expected

Extending classes with additional properties

I have an class object from an external library that I want to add some additional properties to.
Let's say the external class is:
public class ExternalClass
{
public string EXproperty1 {get;set;}
public string EXproperty2 {get;set;}
public string EXproperty3 {get;set;}
public ExternalClass(){}
}
and I have a list of these object which gets populated as
List<ExternalClass> listOfExternalClass=new List<ExternalClass>();
listOfExternalClass=GetListOfExternalClass();
I can extend this class by creating a new class, adding the additional properties and making the external class a property.
public class NewClass
{
public ExternalClass ExternalClass {get;set;}
public string NewProperty1 {get;set;}
public string NewProperty2 {get;set;}
public NewClass(){}
public NewClass(ExternalClass externalClass){
this.ExternalClass=externalClass;
}
}
But to convert by original list of the external classes to a list of the new classes I would have to create a new list of new classes and iterate through the original list creating a new object and adding it to the list, like
List<NewClass> listOfNewClass=new List<NewClass>();
foreach(var externalClass in listOfExternalClass)
{
listOfNewClass.Add(new NewClass(externalClass));
}
I would then be able to access the external properties like
listOfNewClass.FirstOrDefault().ExternalClass.EXproperty1;
Can I do this with inheritance or is there a more efficient method?
Ideally I would like to end up with by calling the properties like:
listOfNewClass.FirstOrDefault().EXproperty1;
This can certainly be done with inheritance. Consider the following.
//Inherit from our external class
public class NewClass: ExternalClass
{
//Note we do not have a copy of an ExternalClass object here.
//This class itself will now have all of its instance members.
public string NewProperty1 {get;set;}
public string NewProperty2 {get;set;}
//If it has parameters include those parameters in NewClass() and add them to base().
//This is important so we don't have to write all the properties ourself.
//In some cases it's even impossible to write to those properties making this approach mandatory.
public NewClass()
{
}
}
Few things to know:
Your code is called a wrapper. This is because it "wraps" another class or group of classes.
You cannot inherit from class marked as sealed.
In C# classes are not sealed by default. If they're sealed the developer has intentionally prevented you from inheriting from the class. This is usually for a good reason.
If you can actually extend the External class that would be easy to accomplish:
public class NewClass: ExternalClass
{
public string NewProperty1 {get;set;}
public string NewProperty2 {get;set;}
public NewClass(){}
public NewClass(ExternalClass externalClass){
// you would have to copy all the properties
this.EXproperty1 = externalClass.EXproperty1;
}
}
Yes inheritance is what you are looking for:
public class ExternalClass
{
public string EXproperty1 { get; set; }
public string EXproperty2 { get; set; }
public string EXproperty3 { get; set; }
public ExternalClass() { }
}
public class NewClass:ExternalClass
{
public string NewProperty1 { get; set; }
public string NewProperty2 { get; set; }
public NewClass() { }
}
If you wish for (or need) delegation instead of a copy you can do:
public class NewClass
{
public ExternalClass ExternalClass {get;set;}
public string NewProperty1 {get;set;}
public string NewProperty2 {get;set;}
public string EXproperty1 {get { return this.ExternalClass.EXproperty1; };set{ this.ExternalClass.EXproperty1 = value; }; }
public string EXproperty2 {get { return this.ExternalClass.EXproperty2; };set{ this.ExternalClass.EXproperty2 = value; }; }
public string EXproperty3 {get { return this.ExternalClass.EXproperty3; };set{ this.ExternalClass.EXproperty3 = value; }; }
public NewClass(){}
public NewClass(ExternalClass externalClass){
this.ExternalClass=externalClass;
}
}
Instead of working against specific types, work against interfaces.
Below I am showing a mix of facade pattern and adapter pattern to 'transform' external data to a well-defined interface (IDocument), effectively abstracting things your are working on.
Example 1 : query about an interface
Here are the types you'll work against:
public interface IDocument {
string Name { get; set; }
}
public interface IMetadata {
string[] Tags { get; set; }
}
This is your own representation, should you need any:
public class RichDocument : IDocument, IMetadata {
public string Name { get; set; }
public string[] Tags { get; set; }
}
This is the wrapper against external data:
(a bastard mix of facade and/or adapter concepts)
public class ExternalClass {
public string Whatever { get; set; }
}
public class ExternalDocument : IDocument /* only a basic object */ {
private readonly ExternalClass _class;
public ExternalDocument(ExternalClass #class) {
_class = #class;
}
public string Name {
get { return _class.Whatever; }
set { _class.Whatever = value; }
}
}
And a demo on how to use all that:
internal class Demo1 {
public Demo1() {
var documents = new List<IDocument> {
new ExternalDocument(new ExternalClass()),
new RichDocument()
};
foreach (var document in documents){
var name = document.Name;
Console.WriteLine(name);
// see if it implements some interface and do something with it
var metadata = document as IMetadata;
if (metadata != null) {
Console.WriteLine(metadata.Tags);
}
}
}
}
Example 2 : query about a component
This is a bit more involved by pushing the concept to treat everything in an uniform manner, you can find it in .NET framework, game development or whatever ...
Definitions you'll work against:
public interface IContainer {
IList<IComponent> Components { get; }
}
public interface IComponent {
// it can be/do anything
}
Some components you'll query about:
public interface IDocument : IComponent {
string Name { get; set; }
}
public interface IMetadata : IComponent {
string[] Tags { get; set; }
}
Your 'internal' type:
public class Container : IContainer {
public Container() {
Components = new List<IComponent>();
}
public IList<IComponent> Components { get; }
}
Your 'wrapper' against external data:
public class ExternalClass {
public string Whatever { get; set; }
}
public class ExternalContainer : IContainer {
private readonly List<IComponent> _components;
public ExternalContainer(ExternalClass #class) {
_components = new List<IComponent> {new ExternalDocument(#class)};
}
public IList<IComponent> Components {
get { return _components; }
}
}
public class ExternalDocument : IDocument {
private readonly ExternalClass _class;
public ExternalDocument(ExternalClass #class) {
_class = #class;
}
public string Name {
get { return _class.Whatever; }
set { _class.Whatever = value; }
}
}
And a usage example:
public class Demo2 {
public Demo2() {
var containers = new List<IContainer> {
new ExternalContainer(new ExternalClass()),
new Container()
};
foreach (var container in containers) {
// query container for some components
var components = container.Components;
var document = components.OfType<IDocument>().FirstOrDefault();
if (document != null) {
Console.WriteLine(document.Name);
}
var metadata = components.OfType<IMetadata>().FirstOrDefault();
if (metadata != null) {
Console.WriteLine(metadata.Tags);
}
}
}
}
Notes
The problem with inheritance is that it is a very rigid approach and generally once you start doing it and at some point you hit a wall and want to revert, it's hard to get out of it.
By working against abstractions things are more flexible and things are decoupled.
Here are two examples that might incite you to change your approach:
Composition over inheritance
Using Components

Collection of various types

In the current system I'm working on I need to have functionality for ammendments.
That being that a user can create an ammendment package and that package contains new version of various domain objects (not structure changes just data changes).
I want to have an "AmmendmentPackage" that contains all of the ammendments that are to be made to various different types of elements.
So far I have
public class AmmendmentPackage : BaseObject
{
public string Name {get;set;}
public string Description { get; set; }
public int MajorVersionNumber { get; set; }
public int MinorVersionNumber { get; set; }
public bool IsGazetted { get; set; }
public AmmendmentPackageState State { get; set; }
}
public class Ammendment<T>
{
public T AmmendedElement{get;set;}
public AmmendmentState State {get;set;}
public ConcurrencyDetails ConcurrencyState { get; set; }
}
How do I go about having the AmmendmentPackage contain number of different Ammentments of various types. I was thinking about using ICollection but then I would have an ICollection<Ammenndment<T>> and I could only have one type of ammendment in the package.
Also was considering using a dictionary but not 100% sure how I would work that in just yet, hopefully I haven't missed something really basic but would appreciate some ideas.
Cheers
This is not possible.
You cannot have a strongly-typed collection that holds different types of objects.
Instead, you should make a non-generic base class or interface and make a collection of those.
You can create a collection of different concrete types that implement the same interface. If you make the interface definition empty, then it can even be applied to any reference type without modifying that type (but you'll have to figure out what operations are available on an AmmendedElement at runtime - I don't recommend this, it is just possible). For example:
using System;
using System.Collections.Generic;
public interface IAnyType { }
public abstract class PackageBase { }
public class Class_1 : IAnyType { public string Class_1_String { get; set; } }
public class Class_2 : IAnyType { public string Class_2_String { get; set; } }
public class AmmendmentPackage : PackageBase
{
public IList<Ammendment<IAnyType>> Ammendments { get; set; }
}
public class Ammendment<T> where T : IAnyType
{
public T AmmendedElement { get; set; }
}
class Program
{
static void Main(string[] args)
{
Ammendment<IAnyType> ammendment_1 = new Ammendment<IAnyType>();
ammendment_1.AmmendedElement = new Class_1();
Ammendment<IAnyType> ammendment_2 = new Ammendment<IAnyType>();
ammendment_2.AmmendedElement = new Class_2();
AmmendmentPackage package = new AmmendmentPackage();
package.Ammendments = new List<Ammendment<IAnyType>>(2);
package.Ammendments.Add(ammendment_1);
package.Ammendments.Add(ammendment_2);
}
}

Categories