Generic objects in c# - c#

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).

Related

C# - Access property in inheriting class

I'm trying to access a generic typed property in a child class. In the below example I recreated my problem. Is there a workaround for this problem, or is it simply not possible? Thanks in advance!
EDIT: It's not possible to declare the collection as A<Model> or A<T>.
public abstract class Model {
public int Id { get; }
}
public interface I<T> where T: Model {
ICollection<T> Results { get; }
}
public abstract class A { }
public class A<T> : A, I<T> where T : Model {
public ICollection<T> Results { get; }
}
public class Example {
A[] col;
void AddSomeModels() {
col = new A[] {
new A<SomeModel>(),
new A<SomeOtherModel>()
}
}
void DoSomethingWithCollection() {
foreach (var a in col) {
// a.Results is not known at this point
// is it possible to achieve this functionality?
}
}
}
You can't do what you intend without some compromises.
First of all, you need to make your interface I<T> covariant in T:
public interface I<out T> where T : Model
{
IEnumerable<T> Results { get; }
}
The first compromise is therefore that T can only be an output. ICollection<T> isn't covariant in T so you'd need to change the type of Results to IEnumerable<T>.
Once you do this, the following is type safe and therefore allowed:
public void DoSomethingWithCollecion()
{
var genericCol = col.OfType<I<Model>>();
foreach (var a in genericCol )
{
//a.Results is now accessible.
}
}

Creating a virtual generic method in C#

I have some base classes like this:
public class AbstractData
{
public int ID { get; set; }
}
public class Person: AbstractData
{
public string Name { get; set; }
}
public class AbstractManager<T> where T: AbstractData
{
public virtual List<T> GetAll()
{
}
public virtual T GetOne(int id)
{
}
}
public class PersonManager: AbstractManager<Person>
{
public override List<Person> GetAll()
{
//...
}
public override Person GetOne(int id)
{
//...
}
}
Now, I have a Windows Forms base class, like this:
public class BaseForm: Form
{
public virtual AbstractManager<T> GetManager<T>() where T: AbstractData
{
return null;
}
}
and a derived form:
public class PersonForm: BaseForm
{
public override AbstractManager<T> GetManager<T>()
{
return new PersonManager();
}
}
The problem is, I keep getting compile errors on the PersonForm class:
Cannot implicitly convert type 'PersonManager' to 'AbstractManager<T>'
Is there a way in which I can create this virtual method and have every class derived from BaseForm return the concrete representation of the AbstractManager?
If I get rid of the generic on the AbstractManager class then I compile OK (with a few code changes), but then the GetAll method can't return a List<T>. It would have to return a List<AbstractData> instead, which causes issues in converting from List<Person> to List<AbstractData>.
Any help would be appreciated.
First off all, please never do this:
class C<T>
{
void M<T>(T t) { }
}
Now we have two things named T both in scope and they are different. This is legal but extremely confusing. Choose better names for your type parameters.
Let's simplify your example:
class FruitBasket<T> where T : Fruit { }
class AppleBasket : FruitBasket<Apple> { }
class C
{
public static FruitBasket<T> GetBasket<T>() where T: Fruit
{
return new AppleBasket();
}
}
Now do you see why this is wrong? What if someone calls C.GetBasket<Orange>() and you hand them a basket of apples?
Any help would be appreciated.
What's step one of getting out of a hole? STOP DIGGING.
You have Genericity Happiness Disease, which is common to C# programmers who are discovering the power of the generic type system and then want to use it for everything whether that makes sense or not. Stop trying to capture all the relationships in your business process in the generic type system; that's not what it was designed for.
The test is: can you say "an apple basket is a basket of apples, where apples are a kind of fruit" and have someone who is not a programmer agree with you? Yes. Can you say "a person manager is an abstract manager of persons where person is a kind of abstract data" and have someone who is not a programmer agree with you? No. Then you are not successfully modeling the business domain in the type system. Start over, avoid generics, and try to come up with relationships between types that make sense.
By declaring
public virtual AbstractManager<T> GetManager<T>() where T: AbstractData
in BaseForm, you're promising that every class derived from BaseForm supports GetManager for any type T. For example, if you had another AbstractData subclass named Invoice, then you could write
personForm.GetManager<Invoice>()
and PersonForm would be expected to return an InvoiceManager.
If you want every class derived from BaseForm to support GetManager for only one type T, then move the T type parameter from GetManager to BaseForm:
public class BaseForm<T>: Form where T: AbstractData
{
public virtual AbstractManager<T> GetManager()
{
return null;
}
}
public class PersonForm: BaseForm<Person>
{
public override AbstractManager<Person> GetManager()
{
return new PersonManager();
}
}
UPDATE: Chad Henderson points out that the Windows Forms designer can't handle generic base classes. If that's a problem for you, then you could try an alternate approach:
public interface IForm<T> where T: AbstractData
{
AbstractManager<T> GetManager();
}
public class BaseForm: Form
{
// ... base functionality that doesn't depend on T ...
}
public class PersonForm: BaseForm, IForm<Person>
{
public AbstractManager<Person> GetManager()
{
return new PersonManager();
}
}

Base class used as an abstract method's parameter?

I'm trying to setup some classes like:
public abstract class AnimalBase {
public string SpeciesName { get; private set; }
public AnimalBase(string speciesName) {
this.SpeciesName = speciesName;
}
public abstract void CopyFrom(AnimalDefaultClass defaultVals);
}
public class Mammal : AnimalBase {
public bool WalksUpright { get; private set; }
public Mammal(string speciesName) : base(speciesName) {
this.CopyFrom(new MammalDefaultClass(speciesName));
}
public override void CopyFrom(MammalDefaultClass defaultVals) {
this.WalksUpright = defaultVals.WalksUpright;
}
public void Cripple() {
this.WalksUpright = false;
}
}
public class MammalDefaultClass : AnimalDefaultClass {
public bool WalksUpright { get; private set; }
public MammalDefaultClass(string speciesName) {
using (var dataStore = theoreticalFactory.GetDataStore()) {
this.WalksUpright = dataStore[speciesName].WalksUpright;
}
}
}
Obviously that's not quite what I'm trying to accomplish, but the idea is:
Several classes (Mammal, Fish, Insect, etc) which inherit from an abstract base (Animal).
Each child class has a corresponding class it can use (in this case to populate mutable default values) as a parameter for a method which was defined as abstract in the base class.
Each of those corresponding classes (MammalDefaultClass, FishDefaultClass, InsectDefaultClass, etc) inherit from a common base class (AnimalDefaultClass).
Those AnimalDefaultClass derivatives exist because each class of Animal will have different properties, but by definition there will always be a class capable of getting those values for any Animal.
My problem is:
That overridden version of CopyFrom(MammalDefaultClass) isn't being recognized as a valid override of the abstract CopyFrom(AnimalDefaultClass), even though MammalDefaultClass inherits from AnimalDefaultClass
Is it possible to specify a base class as an abstract member's parameter? Is there a simple* workaround? Or is this whole thing just laid out wrong?
-edit: my resolution-
After playing around some with MWB and sza's suggestions, I ended up having each subclass implement the method using the base parameter and then cast the input as appropriate, something like:
public class Mammal : AnimalBase {
...
// implements the abstract method from the base class:
public override void CopyFrom(AnimalDefaultClass defaultVals) {
this.CopyFrom((MammalDefaultClass)defaultVals);
}
public void CopyFrom(MammalDefaultClass defaultVals) {
this.WalksUpright = defaultVals.WalksUpright;
}
}
This solution forces me to always implement a CopyFrom(AnimalDefaultClass) , which was the point of the putting the abstract method in the base class in the first place.
I think you can try Abstract Factory pattern. Basically you want to handle some construction logic during the creating the object, and for each different subtype of the Product, you can do differently.
public abstract class AnimalBase
{
public string SpeciesName { get; private set; }
protected AnimalBase(string speciesName)
{
this.SpeciesName = speciesName;
}
}
public class Mammal : AnimalBase
{
public bool WalksUpright { get; set; }
public Mammal(string speciesName) : base(speciesName)
{
}
public void Cripple()
{
this.WalksUpright = false;
}
}
public interface IAnimalFactory<T> where T : AnimalBase
{
T CreateAnAnimal(string speciesName);
}
public class MammalFactory: IAnimalFactory<Mammal>
{
public Mammal CreateAnAnimal(string speciesName)
{
var mammal = new Mammal(speciesName);
var mammalDefault = new MammalDefaultClass(speciesName);
mammal.WalksUpright = mammalDefault.WalksUpright;
return mammal;
}
}
And when you want to create a sub-typed object, you can do e.g.
var mammalFactory = new MammalFactory();
var bunny = mammalFactory.CreateAnAnimal("Bunny");
So it turns out that even though MammalDefaultClass is a subclass of AnimalDefaultClass, you cannot override a function that takes an AnimalDefaultClass with one that takes a MammalDefaultClass.
Consider this block of code:
public class Dinosaur : AnimalDefaultClass;
Dinosaur defaultDinosaur;
public void makeDinosaur(AnimalDefaultClass adc)
{
adc.CopyFrom(defaultDinosaur);
}
MammalDefaultClass m;
makeDinosaur(m);
In this case MammalDefaultClass is a subclass of AnimalDefaultClass, so m can be passed to makeDinosaur as adc. Furthermore the CopyFrom for an AnimalDefaultClass only needs another AnimalDefault class, so I can pass in a dinosaur. But that class is actually a Mammal, and so needs a MammalDefaultClass, which dinosaur is not.
The work around would be to take the original type signature and throw an error if the argument is the wrong type (similar to how arrays act in Java).

how to specify optional anonymous ienumerable parameters in c# abstract method

I have the following base class
public abstract class BaseRepository<T>
{
public abstract IEnumerable<T> GetAll();
}
And a class the inherits it.
public class CustomerRepository: BaseRepository<Customer>
{
public override IEnumerable<Customer>GetAll()
{
return null;
}
}
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
}
what i want to do is using this class
public class Sales
{
public int Id { get; set; }
public int CustomerId {get;set;}
public decimal Total {get;set;}
}
this doesn't work
public class SalesRepository: BaseRepository<Sales>
{
public override IEnumerable<Sales>GetAll(IEnumerable<Customer> Customers)
{
return null;
}
}
My question is, how to I modify my BaseClass to have optional ienumerable parameters of that i can then use as needed.
The GetAll(IEnumerable<Customer> Customers) function amounts to a new method. It does not have the same signature of the base, and so cannot be overridden in this way. The SalesRepository class, if it is to be a BaseRepository<Sales>, must implement the GetAll() method as is.
You can do this change
public class SalesRepository : BaseRepository<Sales>
{
public override IEnumerable<Sales> GetAll()
{
return GetAll(null);
}
public IEnumerable<Sales> GetAll(IEnumerable<Customer> Customers)
{
return null;
}
}
BaseRepository<Sales> rep = new SalesRepository();
rep.GetAll();
this will call overridden version and makes a call to GetAll(null).
To pass value to GetAll() method you need to have do the following
SalesRepository srep = new SalesRepository();
srep.GetAll(new Customer[] { new Customer() });
You can either mark parameter as optional or you can make overloads to the method in your base class, both of which will result in the same thing. When you mark a parameter as optional the compiler simply makes the overloads for you.
Ultimately you probably need to make two methods in your base class and then either hide one (make private) in your implementation of each parent class or have it throw an error. If you can figure out a good way to have default values then that may work as well.

Implicitly cast a generic type to a non-generic equivalent

Given the following classes:
public abstract class MyRecordClass
{
public int id { get; private set; }
}
public class ExampleMyRecordClass : MyRecordClass {}
public enum SomeIntEnum : int {}
public class MyList<T, E> : IList<T>
where T : MyRecordClass
{
}
public class MyOtherClass
{
public void MyMethod(MyList<T, E> list) {}
}
, I'd like call the method like this:
MyList<ExampleMyRecordClass, SomeIntEnum> myList;
MyOtherClass myOtherClass;
myOtherClass.MyMethod(myList);
However, this won't actually work if passing a list of type MyList<ExampleMyRecordClass, SomeIntEnum>, since implicit upcasts don't work in generic types. Since all I really want is the property id, I can, of course, explicitly implement a property or method in MyList<T, E> that returns a new collection with this information.
What I'd prefer to do is have this done implicitly. Is there a way (an implicit operator, perhaps, or an additional interface to implement in MyList<T, E>) to make this possible?
I'm not sure what exactly you're looking for, but if you make the following change it compiles and runs just fine:
public class MyOtherClass
{
public void MyMethod<T, E>(MyList<T, E> list) where T : MyRecordClass { }
}
Are you perhaps looking for covariance?
public class MyList<T, E> : IList<T>, IReadOnlyList<T>
where T : MyRecordClass
{
}
public class MyOtherClass
{
public void MyMethod(IReadOnlyList<MyRecordClass> list) { }
}
Usage:
MyList<ExampleMyRecordClass, SomeIntEnum> myList;
MyOtherClass myOtherClass;
myOtherClass.MyMethod(myList);
IReadOnlyList<T> Interface:
public interface IReadOnlyList<out T> : IEnumerable<T>
{
int Count { get; }
T this[int index] { get; }
}

Categories

Resources