Generalize a generic class - c#

I have written a Collection like this:
class AnimalCollection<TValue> where TValue : Animal, new()
{
void Add(TValue value){};
void AddNew()
{
Add(new TValue());
}
}
I have some Classes which are derived from Animal:
class Animal
{
string Name;
}
class Fish : Animal
{
Fish(){};
}
class Mammal : Animal
{
Mammal(){};
}
As next i want to treat all collections the same way.
static void Main(string[] args)
{
var FishAquarium = new AnimalCollection<Fish>();
var MammalEnclosure = new AnimalCollection<Mammal>();
foo(FishAquarium);
foo(MammalEnclosure);
}
Question 1: I want to pass every AnimalCollection, which type need 'zoo'?
static void foo(AnimalCollection<Animal> zoo)
{
foreach(var animal in Zoo)
Console.WriteLine(animal.Name);
zoo.AddNew();
}
Question 2: What is the best practice to generalize a generic class?
Update:
More specific, i have a class which get any AnimalCollection.
class ZooController
{
public AnimalCollection<Animal> Animals{get; set;}
}

Generics would work:
static void foo<T>(AnimalCollection<T> zoo) where T : Animal, new()
{...}
However, it is usually not a good idea to roll your own collection types - it tends to create more confusion than it helps. You may want to consider justList<T>, or IList<T> at a push.
You say you don't want to use generics; that is IMO a silly decision since they solve exactly this problem, but you can also use covariance; if you have:
interface IAnimalCollection<out TValue> : IEnumerable<TValue>
{
void AddNew();
}
and:
class AnimalCollection<TValue> : IAnimalCollection<TValue>
where TValue : Animal, new()
{...}
then you can use:
static void foo(IAnimalCollection<Animal> zoo)
{
foreach (var animal in zoo)
Console.WriteLine(animal.Name);
zoo.AddNew();
}
and your code:
var FishAquarium = new AnimalCollection<Fish>();
var MammalEnclosure = new AnimalCollection<Mammal>();
foo(FishAquarium);
foo(MammalEnclosure);
will work fine; but - this is making work for no reason - simple generics via the foo<T> method shown above is simpler and more direct.

Try this approach:
class Program
{
static void Main(string[] args)
{
List<IAnimal> animals = new List<IAnimal>() { new Animal("Fuffy"), new Fish("Fishy"), new Mammal("Mommy") };
OutputAnimalsNames(animals);
}
private static void OutputAnimalsNames(List<IAnimal> animals)
{
foreach (IAnimal animal in animals)
{
Console.WriteLine(animal.Name);
}
}
}
public interface IAnimal
{
Guid Guid { get; }
string Name { get; }
}
public class Animal : IAnimal
{
public Guid Guid { get; private set; }
public string Name { get; set; }
public Animal(string name)
{
this.Name = name;
this.Guid = Guid.NewGuid();
}
}
public class Fish : Animal
{
public Fish(string name) : base(name)
{
}
}
public class Mammal : Animal
{
public Mammal(string name) : base(name)
{
}
}

Related

How can I get the name of a class through a reference to an instance of a subclass?

How can I get the name of a class through a reference to an instance of a subclass?
For example,
public class BaseClass
{
public void ClassName()
{
// How can I get the name of the base class "BaseClass" here, without having to hardcode "BaseClass"?
Console.WriteLine(this.GetType().Name);
}
}
public class SubClass: BaseClass
{
public void ClassName()
{
base.ClassName();
Console.WriteLine(this.GetType().Name);
}
}
public static void Main(string[] args)
{
SubClass MyObject = new SubClass();
MyObject.ClassName();
}
The output is
SubClass
SubClass
But I want
BaseClass
SubClass
Thanks.
Generic Method
Probably the cleanest approach:
public static class TypeHelperExtensions
{
public static string GetTypeName<T>(this T Object)
{
return typeof(T).Name;
}
}
And then:
public class BaseClass
{
public virtual void ClassName()
{
// How can I get the name of the base class "BaseClass" here, without having to hardcode "BaseClass"?
Console.WriteLine(this.GetTypeName());
}
}
public class SubClass: BaseClass
{
public override void ClassName()
{
base.ClassName();
Console.WriteLine(this.GetTypeName());
}
}
nameof()
public class BaseClass
{
public virtual void ClassName()
{
// How can I get the name of the base class "BaseClass" here, without having to hardcode "BaseClass"?
Console.WriteLine(nameof(BaseClass));
}
}
public class SubClass: BaseClass
{
public override void ClassName()
{
base.ClassName();
Console.WriteLine(nameof(SubClass));
}
}
Reflection
public class BaseClass
{
public virtual void ClassName()
{
// If you know you will have only one parent
var b = type.BaseType.Name
}
}
if you don't know the structure you may have to do something like the following:
private bool _ignoreMe;
public void ClassName()
{
var b = this.GetType().GetField(nameof(_ignoreMe), BindingFlags.NonPublic | BindingFlags.Instance).DeclaringType;
}

Implementing interface properties in interfaces

I need to create a dll file which contains all the interfaces of the classes but doesn't contain any class.
Because I use these interfaces for a lot of classes it's must be like that:
public interface IClassA
{
string Word { get; }
}
public interface ITest<TClassA> where TClassA : IClassA
{
TClassA A { get; }
}
Example of two classes that implements these interfaces the way I want:
public class ClassA : IClassA
{
public string Word
{
get;
private set;
}
public string Sentence
{
get;
private set;
}
public ClassA(string word, string sentence)
{
this.Word = word;
this.Sentence = sentence;
}
}
public class Test : ITest<ClassA>
{
public ClassA A
{
get;
private set;
}
public Test(ClassA a)
{
this.A = a;
}
}
And I want to do something like that in the main program:
public static void Main(string[] args)
{
ClassA a = new ClassA("hey", "hey world!");
Test t = new Test(a);
Print((ITest<IClassA>)t);
}
public static void Print(ITest<IClassA> t)
{
Console.WriteLine(t.A.Word);
}
But this casting: (ITest<IClassA>)t makes a run time error.
How can I solve it?
thanks!
You should declare Test as
public class Test : ITest<IClassA>
instead of ITest<ClassA>.
Or declare ITest<TClassA> to be covariant on TClassA:
public interface ITest<out TClassA> where TClassA : IClassA
The Test-class implements the concrete ClassA (public class Test : ITest<ClassA>).
So you're trying to cast an ITest<ClassA> to ITest<IClassA> which obviously fails.
If you let the Test-class implement IClassA, the cast works:
public class Test : ITest<IClassA>
{
public IClassA A
{
get; private set;
}
public Test(IClassA a)
{
this.A = a;
}
}

How can you implement an interface with a generic method?

Consider the following classes and interfaces:
interface INameable
{
string Name { get; }
}
interface IRepository<T>
{
void Add(T obj);
IEnumerable<T> Values { get; }
}
class Person : INameable
{
public string Name { get; set; }
public int Age { get; set; }
}
class Car : INameable
{
public string Name { get; set; }
public string Model { get; set; }
}
I now would like to create a Repository class that implements both IRepository<Car> and IRepository<Person>. Here is a sample implementation:
class Repository : IRepository<Car>, IRepository<Person>
{
Dictionary<string, object> values = new Dictionary<string, object>();
void AddValue(INameable o)
{
values.Add(o.Name, o);
}
IEnumerable<T> ValuesOfType<T>()
{
return values.Values.OfType<T>();
}
void IRepository<Car>.Add(Car obj)
{
AddValue(obj);
}
void IRepository<Person>.Add(Person obj)
{
AddValue(obj);
}
IEnumerable<Car> IRepository<Car>.Values
{
get { return ValuesOfType<Car>(); }
}
IEnumerable<Person> IRepository<Person>.Values
{
get { return ValuesOfType<Person>(); }
}
}
This works exactly as expected. However, it is very repetitive; the code for the implementation of IRepository<Person> and IRepository<Car> is nearly exactly the same.
What I would like to do is implement IRepository for all T where T is a INameable. I tried this:
class Repository2 : IRepository<Car>, IRepository<Person>
{
// same as before
Dictionary<string, object> values = new Dictionary<string, object>();
void AddValue(INameable o)
{
values.Add(o.Name, o);
}
IEnumerable<T> ValuesOfType<T>()
{
return values.Values.OfType<T>();
}
// using generics to implement both the interfaces
void Add<T>(T obj) where T : INameable
{
AddValue(obj);
}
void Values<T>() where T : INameable
{
return ValuesOfType<T>();
}
}
However I get errors like:
ConsoleApp.Repository2' does not implement interface member 'ConsoleApp.IRepository<ConsoleApp.Car>.Add(ConsoleApp.Car)'
I'm not sure why the Add<T> and Vales<T> methods aren't being matched - both T's can be set to Person and Car, and then they would exactly match the method type needed.
Finally, I tried:
class Repository3 : IRepository<T> where T is INameable {... }
However, I get an error "Constraints are not allowed on non-generic declarations".
What is the best way of solving this problem?
Note that I am doing this as a method to simply access to a DbContext class (which has references to every table in the application), so instead of passing the full database to each controller, I only pass the data that is needed. I was doing this to better separate the database from the rest of the app, and to improve testability. If there is a better way of doing this that could also help.
You could have an abstract class with the implementation and then just inherit it for specific types.
public interface INameable
{
string Name { get; }
}
public interface IRepository<T>
{
void Add( T obj );
IEnumerable<T> Values { get; }
}
public class Person : INameable
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Car : INameable
{
public string Name { get; set; }
public string Model { get; set; }
}
public abstract class AbstractRepository<T> : IRepository<T>
where T : INameable
{
// same as before
Dictionary<string, object> values = new Dictionary<string, object>();
void AddValue( INameable o )
{
values.Add( o.Name, o );
}
IEnumerable<T> ValuesOfType<T>()
{
return values.Values.OfType<T>();
}
// using generics to implement both the interfaces
public void Add( T obj )
{
AddValue( obj );
}
public IEnumerable<T> Values
{
get
{
return ValuesOfType<T>();
}
}
}
public class CarRepository : AbstractRepository<Car> { }
public class PersonRepository : AbstractRepository<Person> { }
In my experience, it is much easier that all the entities, that are to be added to some repository, conform to some interface, say IBaseObject:
interface IRepository
{
void Add(IBaseObject obj);
IEnumerable<IBaseObject> Values { get; }
}
This generally ends up being a good solution because in IBaseObject you could have an identifier so you know when to add or an update an existing record.
update:
Another approach is to use the following pattern, again still relying on IBaseObject:
interface IRepository
{
void Add(T obj) where T : IBaseObject;
IEnumerable<T> GetValues() where T : IBaseObject;
}
I think, you should create class that creates repositories. Something like this:
class Repository<T> : IRepository<T>
where T : INameable
{
Dictionary<string, T> values = new Dictionary<string, T>();
void AddValue(T o)
{
values.Add(o.Name, o);
}
public void Add(T obj)
{
AddValue(obj);
}
public IEnumerable<T> Values
{
get { return values.Values; }
}
}
class UnitOfWork
{
private readonly Dictionary<Type, object> _repositories = new Dictionary<Type, object>();
public IRepository<T> GetRepository<T>()
where T : INameable
{
object repository;
if (!_repositories.TryGetValue(typeof (T), out repository))
{
repository = new Repository<T>();
_repositories[typeof (T)] = repository;
}
return (IRepository<T>)repository;
}
}
And use it like that:
var unitOfWork = new UnitOfWork();
unitOfWork.GetRepository<Car>().Add(new Car {Name = "Audi"});
unitOfWork.GetRepository<Car>().Add(new Car { Name = "BMW" });
foreach (var car in unitOfWork.GetRepository<Car>().Values)
Console.WriteLine(car.Name);

Identical classes with different names

I want to be a little be more descriptive in my class names. I have three identical classes that look like this:
public class Dog
{
public string name;
public int id;
public Dog(){}
public Dog(DataRow dr)
{
name = dr["Name"];
id = dr["Id"];
}
}
public class Cat
{
public string name;
public int id;
public Cat(){}
public Cat(DataRow dr)
{
name = dr["Name"];
id = dr["Id"];
}
}
public class Horse
{
public string name;
public int horseId;
public Horse(){}
public Horse(DataRow dr)
{
name = dr["Name"];
horseId= dr["horseId"];
}
}
How do I avoid code duplication by using a base class? What are the best practicies? pplease note that horse has a property called HorseId instead of Id. Thanks.
Use inheritance.
public class Animal
{
public string name;
public int id;
public Animal() {}
public Animal(DataRow dr)
{
name = (string)dr["Name"];
id = (int)dr["Id"];
}
}
// unfortunately, constructors aren't inherited automatically in C#.
public class Cat : Animal
{
public Cat() : base() {}
public Cat(DataRow dr) : base(dr) {}
}
public class Dog : Animal
{
public Dog() : base() {}
public Dog(DataRow dr) : base(dr) {}
}
public class Horse: Animal
{
public int horseId { get { return id; } set { id = value; } }
public Horse() : base() {}
public Horse(DataRow dr) : base(dr) {}
}
EDIT: as Blorgbeard says, you can make Animal an abstract class if you want - that will prevent instantiation (new Animal() will be illegal; client code will have to pick a specific subclass).
I would make an interface called IAnimal that has properties name and id and have all 3 classes above implement this interface. Note is is slightly different than what you have here, as what you have here shows public variables, not public properties. If you want to maintain variables, then I would use a base class Animal with public variables name and id and convert horseId to a property that, interally, gets and sets the base id property like this public int horseId { get { return base.id; } set { base.id = value; } }
I'd do something like this - an abstract base class.
public abstract class Animal {
public string name;
public int id;
protected Animal() {}
protected Animal(DataRow dr) {
name = (string)dr["Name"];
id = (int)dr["Id"];
}
}
public class Cat : Animal {
public Cat() : base() {}
public Cat(DataRow dr) : base(dr) {}
}
Then just add a property to Horse (still leaving id as well)
public class Horse : Animal {
public int horseid { get { return id; } set { id = value; } }
public Horse() : base() {}
public Horse(DataRow dr) : base(dr) {}
}
This method doesn't allow you remove/hide id in the Horse class, so you will have both id and horseid, but they will use the same variable underneath.
As far as some good examples on object oriented design, I'd recommend two books.
The Object Oriented Thought Process
Agile Principles, Patterns and Practices in C# by Robert C. Martin. This book is just awesome at explaining great principles of OOP.

How to create a method that takes a Generic base type

I have something similar to the following, but I cannot provide House or Farm objects to the PrintShelterAddress method:
public interface IAnimal { };
public interface IDomesticAnimal : IAnimal { };
public interface IHouseAnimal : IDomesticAnimal { };
public interface IFarmAnimal : IDomesticAnimal { };
public class Animal : IAnimal { }
public class DomesticAnimal : Animal, IDomesticAnimal { }
public class Lion : Animal { }
public class Cat : DomesticAnimal, IHouseAnimal { }
public class Horse : DomesticAnimal, IFarmAnimal { }
public interface IAnimalShelter<T> where T : IDomesticAnimal { String Address { get; set; } };
public interface IHouse : IAnimalShelter<IHouseAnimal> { };
public interface IFarm : IAnimalShelter<IFarmAnimal> { };
public class AnimalShelter<T> : IAnimalShelter<T> where T : IDomesticAnimal { public String Address { get; set; } }
public class House : AnimalShelter<IHouseAnimal>, IHouse { }
public class Farm : AnimalShelter<IFarmAnimal>, IFarm { }
class Program
{
static void Main(string[] args)
{
PrintShelterAddress(new House() { Address = "MyHouse" }); // Error: argument type 'House' is not assignable to parameter type 'IAnimalShelter<IDomesticAnimal>'
// This makes sense as House is a IAnimalShelter<IHouseAnimal>
// and IHouseAnimal cannot be cast to its parent IDomesticAnimal
IAnimalShelter<IDomesticAnimal> nonDescriptShelter = new House(); // InvalidCastException: Unable to cast object of type 'House' to type 'IAnimalShelter`1[IDomesticAnimal]'.
}
static void PrintShelterAddress(IAnimalShelter<IDomesticAnimal> nonDescriptShelter)
{
Console.WriteLine(nonDescriptShelter.Address as string);
}
}
What I tried:
Manual cast:
PrintShelterAddress((IAnimalShelter<IDomesticAnimal>)new House() { Address = "MyHouse" });
Compiles but as expected, throws a run-time exception: Unable to cast object of type 'House' to type 'IAnimalShelter`1[IDomesticAnimal]'.
What else I tried:
static void PrintShelterAddress(dynamic nonDescriptShelter)
{
Console.WriteLine(nonDescriptShelter.Address);
}
This works but I am not keen on using dynamic.
My best solution:
Adding an non generic base interface to IAnimalShelter<T> and using that:
public interface IAnimalShelter { String Address { get; set; } };
public interface IAnimalShelter<T> : IAnimalShelter where T : IDomesticAnimal { };
static void PrintShelterAddress(IAnimalShelter nonDescriptShelter) { ... }
So...
Is there a better solution than using dynamic or adding a base interface to IAnimalShelter<T>?
Hmm.. Try to make your interfaces covariant:
public interface IAnimalShelter<out T> : .....

Categories

Resources