I'm trying to create an abstract generic class which inherits from another abstract generic class.
Here's what I have so far
public abstract class BaseClass {
public long Id { get; private set; }
public BaseClass(long id) {
this.Id = id;
}
}
public abstract class BaseClass<T> : BaseClass where T : BaseClass {
protected BaseClass(long id)
: base(id) {
}
public static T Get(long id) {
T item;
return TryGet(id, out item) ? item : default(T);
}
public static bool TryGet(long id, out T item) {
item = null; // This is where I call the cache but for this example I've removed so it will compile
if (item != null) { return true; }
else {
// Call TryGetFallback method
return false;
}
}
protected abstract T TryGetFallback(long id);
}
public abstract class DerivedClass : BaseClass<DerivedClass> {
public String Name { get; private set; }
public DerivedClass(long id, String name)
: base(id) {
this.Name = name;
}
}
public class DerivedDerivedClass : DerivedClass {
protected override DerivedDerivedClass TryGetFallback(long id) {
// Handle the try get fallback
}
}
The TryGetFallback method on the DerivedDerivedClass causes a compiler error.
First you need to fix your BaseClass<T> implementation to not have a recursive type constraint.
public abstract class BaseClass<T> : BaseClass where T : new() {
//snip
}
Then you can use it in your derived class, for example I will make it use int for the generic type parameter:
public abstract class DerivedClass : BaseClass<int> {
//snip
}
And now if you compile it will warn you that 'DerivedDerivedClass' does not implement inherited abstract member 'BaseClass<int>.TryGetFallback(long)'
Thanks for the tips #DavidG it's helped me to solve the problem with the following code
public abstract class BaseClass {
public long Id { get; private set; }
public BaseClass(long id) {
this.Id = id;
}
}
public abstract class BaseClass<T> : BaseClass where T : BaseClass<T>, new() {
protected BaseClass(long id) : base(id) { }
public static T Get(long id) {
T item;
return TryGet(id, out item) ? item : default(T);
}
public static bool TryGet(long id, out T item) {
item = null; // Try to get item from cache here
if (item != null) { return true; }
else {
T obj = new T();
item = obj.TryGetFallback(id);
return item != null;
}
}
protected abstract T TryGetFallback(long id);
}
public abstract class DerivedClass<T> : BaseClass<T> where T : DerivedClass<T>, new() {
public String Name { get; private set; }
public DerivedClass() : base(0) { }
public DerivedClass(long id, String name)
: base(id) {
this.Name = name;
}
protected abstract override T TryGetFallback(long id);
}
public class DerivedDerivedClass : DerivedClass<DerivedDerivedClass> {
public DerivedDerivedClass() {
}
protected override DerivedDerivedClass TryGetFallback(long id) {
throw new NotImplementedException();
}
}
Related
I am trying to implement a repository pattern, however I don't understand how its possible when entities have id's of different types. Currently I have to fallback to using object, while I would really like to use the specific type of the id of the entity the repository is holding.
interface IEntity
{
object GetId();
}
class Foo : IEntity
{
private string id;
public Foo(string id)
{
this.id = id;
}
public object GetId()
{
return id;
}
}
class Bar : IEntity
{
private int id;
public Bar(int id)
{
this.id = id;
}
public object GetId()
{
return id;
}
}
class Repository<T> where T : IEntity
{
private Dictionary<object, T> entities = new Dictionary<object, T>();
public IEnumerable<T> List => entities.Values.AsEnumerable();
public void Add(T entity)
{
entities.Add(entity.GetId(), entity);
}
public T Get(object id)
{
return entities[id];
}
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo("0");
var bar = new Bar(0);
var fooRepo = new Repository<Foo>();
fooRepo.Add(foo);
fooRepo.Get(foo.GetId());
var barRepo = new Repository<Bar>();
barRepo.Add(bar);
barRepo.Get(bar.GetId());
}
}
I also tried something like:
class Repository<Id, Value> where Value : IEntity
{
private Dictionary<Id, Value> entities = new Dictionary<Id, Value>();
public IEnumerable<Value> List => entities.Values.AsEnumerable();
public void Add(Value entity) // But got stuck here, I don't want to pass in Id as separate parameter, I want it auto magically from the interface.
{
entities.Add(entity.GetId(), entity);
}
public Value Get(Id id)
{
return entities[id];
}
}
You can add a generic type of the key to IEntity. E.g.,
interface IEntity<TId>
{
TId GetId();
}
class Foo : IEntity<string>
{
private string id;
public Foo(string id)
{
this.id = id;
}
public string GetId()
{
return id;
}
}
class Repository<TEntity, TId> where TEntity : IEntity<TId>
{
private Dictionary<TId, TEntity> entities = new Dictionary<TId, TEntity>();
public void Add(TEntity entity)
{
entities.Add(entity.GetId(), entity);
}
public TEntity Get(TId id)
{
return entities[id];
}
}
Joel's solution could be extended to allow for variance. The same way generic collections implement both IEnumerable and IEnumerable<T>.
Entity
interface IEntity
{
object GetId();
}
interface IEntity<TId> : IEntity
{
new TId GetId();
}
abstract class EntityBase<TId> : IEntity<TId>
{
protected TId id;
protected EntityBase(TId id)
{
this.id = id;
}
public TId GetId() => id;
object IEntity.GetId() => GetId();
}
Repository
abstract class Repository
{
protected Dictionary<object, IEntity> entities;
protected Repository()
{
entities = new Dictionary<object, IEntity>();
}
public virtual void Add(IEntity entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));
entities.Add(entity.GetId(), entity);
}
public virtual IEntity Get(object id)
{
if (id == null) throw new ArgumentNullException(nameof(id));
return entities[id];
}
}
abstract class Repository<TId, TEntity> : Repository
where TEntity : class, IEntity<TId>
{
protected Repository() : base() { }
public override void Add(IEntity entity)
{
Add((TEntity)entity);
}
public override IEntity Get(object id)
{
return Get((TId)id);
}
public void Add(TEntity entity)
{
if (entity == null) throw new ArgumentNullException(nameof(entity));
entities.Add(entity.GetId(), entity);
}
public TEntity Get(TId id)
{
if (id == null) throw new ArgumentNullException(nameof(id));
return (TEntity)entities[id];
}
}
Use Case
class Foo : EntityBase<string>
{
public Foo(string id) : base(id) { }
}
class Bar : EntityBase<int>
{
public Bar(int id) : base(id) { }
}
class FooRepository : Repository<string, Foo>
{
public FooRepository() { }
}
class BarRepository : Repository<int, Bar>
{
public BarRepository() { }
}
Test
[TestMethod]
public void IEntitySupport()
{
// use IEntity and object
IEntity bar = new Bar(1);
Repository barRepository = new BarRepository();
barRepository.Add(bar);
var bar2 = barRepository.Get((object)1);
Assert.AreSame(bar, bar2);
}
[TestMethod]
public void TEntitySupport()
{
// use TEntity and TId
var foo = new Foo("a");
var fooRepository = new FooRepository();
fooRepository.Add(foo);
var foo2 = fooRepository.Get("a");
Assert.AreSame(foo, foo2);
}
Please see this structure (from here):
public abstract class AbstractPage<T> where T : AbstractPageEmenetsMap, new()
{
protected readonly string url;
protected VendorInfo vendorInfo;
public AbstractPage(VendorInfo vendorInfo)
{
this.vendorInfo = vendorInfo;
this.url = this.vendorInfo.Url;
}
public void Navigate()
{
WebDriver.Driver.Navigate().GoToUrl(this.url);
}
protected T Map
{
get { return new T(); }
}
}
public abstract class AbstractPage<M, V> : AbstractPage<M>, ITest
where M : AbstractPageEmenetsMap, new()
where V : AbstractPageValidator<M>, new()
{
public AbstractPage(VendorInfo vendorInfo)
: base(vendorInfo) { }
public V Validate()
{
return new V();
}
public void Login();
{
throw new System.NotImplementedException();
}
public void Logout();
{
throw new System.NotImplementedException();
}
}
And i want to add interface with some operations
public interface ITest
{
void Login();
void Logout();
}
Now this is Son class:
public class GmailPage : AbstractPage<GmailPageElementsMap, GmailPageValidator>, ITest
{
public GmailPage() : base("http:...") { }
}
Class that holds all the elements:
public IWebElement EmailAddressTextBox
{
get
{
return WebDriver.WebDriverWait.Until(ExpectedConditions.ElementIsVisible(By.Id("identifierId")));
}
}
And validator:
public class GmailPageValidator : AbstractPageValidator<GmailPageElementsMap>
{
}
As you can see i implement ITest from my Gmail class but i don't received any compile error although i do not add this 2 interface methods (Login and Logout).
This is because those methods are implemented in the parent AbstractPage. If you want to force GmailPage (and all other derived classes) to implement Login() and Logout() declare them as abstract in the parent AbstractPage class
public abstract class AbstractPage<M, V> : AbstractPage<M>, ITest
where M : AbstractPageEmenetsMap, new()
where V : AbstractPageValidator<M>, new()
{
public AbstractPage(VendorInfo vendorInfo) : base(vendorInfo) { }
public V Validate()
{
return new V();
}
public abstract void Login();
public abstract void Logout();
}
And override in GmailPage
public class GmailPage : AbstractPage<GmailPageElementsMap, GmailPageValidator>
{
public GmailPage() : base("http:...") { }
public override void Login()
{
throw new System.NotImplementedException();
}
public override void Logout()
{
throw new System.NotImplementedException();
}
}
Building off of the work done here, I've defined a generic, abstract base class for enumerations, like so:
public abstract class Enumeration<T> : IEquatable<T> where T : Enumeration<T>
{
private static IEnumerable<T> enumerateAllValues()
{
// Obviously use some caching here
var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
return fields.Select(f => f.GetValue(null)).OfType<T>();
}
internal static IEnumerable<T> AllValues {get { return enumerateAllValues();}}
protected Enumeration(int value, string displayName)
{
if (!typeof(T).IsSealed)
throw new NotSupportedException($"Value objects must be sealed, {typeof(T).Name} is not.");
this.Value = value;
this.DisplayName = displayName;
}
protected int Value { get; }
protected string DisplayName { get; }
public override string ToString() { return DisplayName; }
// IEquatable implementation based solely on this.Value
}
And a static, non-generic helper class to parse and list values of an enum:
public static class Enumeration
{
public static IEnumerable<T> GetAllValues<T>() where T : Enumeration<T>
{
return Enumeration<T>.AllValues;
}
// Other helper methods, e.g. T Parse(int), bool TryParse(int, out T), etc.
}
Now, I derive from this with another abstract class to represent a certain class of enumerations that have something in common:
public abstract class AnimalTrait<T> : Enumeration<AnimalTrait<T>>
{
protected AnimalTrait(int value, string displayName) : base(value, displayName) { ; }
}
So far so good. As an example the concrete class deriving from this might be DogTrait, or FishTrait, etc. Knowing that all animal traits can be paired with a value, and supposing that the value of an animal trait is always a string, I then define another abstract class like so:
public struct AnimalTraitValuePair<TAnimalTrait> where TAnimalTrait : AnimalTrait<TAnimalTrait>
{
public TAnimalTrait AnimalTrait { get; }
public string Value { get; } // Analogy breaks down here, but lets assume we know that the values of animal traits are always strings.
public AnimalTraitValuePair(TAnimalTrait animalTrait, string value)
{
this.AnimalTrait = animalTrait;
this.Value = value;
}
public override string ToString()
{
return $"[{AnimalTrait}, {Value}]";
}
}
Similar to deriving from KeyValuePair<TAnimalTrait, string> where TAnimalTrait : AnimalTrait<TAnimalTrait>, which I would do if it wasn't a struct.
Now when I go to define the Animal class that holds the name of the animal and it's list of AnimalTrait's with their associated values, i.e. a list of AnimalTraitValuePair<TAnimal>, I run into a problem:
public abstract class Animal<TAnimal, TAnimalTrait> :
where TAnimal : Animal<TAnimal, TAnimalTrait>
where TAnimalTrait : AnimalTrait<TAnimalTrait>
{
private readonly IList<AnimalTraitValuePair<TAnimalTrait>> animalTraitValuePairList;
// All animals have a name
public string Name {get;}
protected Animal(string name, IEnumerable<AnimalTraitValuePair<TAnimalTrait>> animalTraitValuePairs)
{
animalTraitValuePairList = animalTraitValuePairs.ToList();
this.Name = name;
}
public string this[TAnimalTrait animalTrait]
{
get
{
return animalTraitValuePairList.First(atvp => atvp.AnimalTrait == animalTrait).Value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
// !!!! BREAKS HERE !!!!
foreach (var animalTrait in Enumeration.GetAllValues<AnimalTrait<TAnimalTrait>>()) // This works...
//foreach (var animalTrait in Enumeration.GetAllValues<TAnimalTrait>()) // ...but this doesn't
{
sb.AppendLine($"{this.Name}'s traits:");
sb.AppendLine($"[{animalTrait}, {animalTrait.Value}]");
}
return sb.ToString();
}
}
I get this compiler error:
The type 'TAnimalTrait' cannot be used as type parameter 'T' in the generic type or method 'Enumeration.GetAllValues<T>()'. There is no implicit reference conversion from 'TAnimalTrait' to 'Maxim.Common.Enums.Enumeration<TAnimalTrait>'
Why can't I use TAnimalTrait directly? Is not TAnimalTrait restricted to be a class of AnimalTrait<TAnimalTrait>, which we know is an Enumeration and therefore can be upcasted two levels to the base Enumeration<T>? Is the one that compiles "correct" and give me the behavior I want?
There were a number of problems with your code, and I lost track of all the things I had to change, but here's a working snippet:
void Main()
{
Console.WriteLine(Dog.Fido.ToString());
}
public abstract class Enumeration<T> where T : Enumeration<T>
{
private static IEnumerable<T> enumerateAllValues()
{
// Obviously use some caching here
var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
return fields.Select(f => f.GetValue(null)).OfType<T>();
}
internal static IEnumerable<T> AllValues { get { return enumerateAllValues();}}
protected Enumeration(int value, string displayName)
{
if (!typeof(T).IsSealed)
throw new NotSupportedException($"Value objects must be sealed, {typeof(T).Name} is not.");
this.Value = value;
this.DisplayName = displayName;
}
protected int Value { get; }
protected string DisplayName { get; }
public override string ToString() { return DisplayName; }
// IEquatable implementation based solely on this.Value
}
public static class Enumeration
{
public static IEnumerable<T> GetAllValues<T>() where T : Enumeration<T>
{
return Enumeration<T>.AllValues;
}
// Other helper methods, e.g. T Parse(int), bool TryParse(int, out T), etc.
}
public abstract class AnimalTrait<T> : Enumeration<T>
where T : AnimalTrait<T>
{
protected AnimalTrait(int value, string displayName) : base(value, displayName) {; }
}
public struct AnimalTraitValuePair<TAnimalTrait> where TAnimalTrait : AnimalTrait<TAnimalTrait>
{
public TAnimalTrait AnimalTrait { get; }
public string Value { get; } // Analogy breaks down here, but lets assume we know that the values of animal traits are always strings.
public AnimalTraitValuePair(TAnimalTrait animalTrait, string value)
{
this.AnimalTrait = animalTrait;
this.Value = value;
}
public override string ToString()
{
return $"[{AnimalTrait}, {Value}]";
}
}
public abstract class Animal<TAnimal, TAnimalTrait> : Enumeration<TAnimal>
where TAnimal : Animal<TAnimal, TAnimalTrait>
where TAnimalTrait : AnimalTrait<TAnimalTrait>
{
private readonly IList<AnimalTraitValuePair<TAnimalTrait>> animalTraitValuePairList;
// All animals have a name
public string Name { get; }
protected Animal(int i, string name, IEnumerable<AnimalTraitValuePair<TAnimalTrait>> animalTraitValuePairs)
: base(i, name)
{
animalTraitValuePairList = animalTraitValuePairs.ToList();
this.Name = name;
}
public string this[TAnimalTrait animalTrait]
{
get
{
return animalTraitValuePairList.First(atvp => atvp.AnimalTrait == animalTrait).Value;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine($"{this.Name}'s traits:");
foreach (var animalTrait in Enumeration.GetAllValues<TAnimalTrait>())
{
sb.AppendLine($"[{animalTrait}, {this[animalTrait]}]");
}
return sb.ToString();
}
}
public sealed class DogTrait : AnimalTrait<DogTrait>
{
public DogTrait(int i, string name)
: base(i, name)
{ }
public static DogTrait Color = new DogTrait(1, "Color");
public static DogTrait Size = new DogTrait(2, "Size");
}
public sealed class Dog : Animal<Dog, DogTrait>
{
public Dog(int i, string name, IEnumerable<AnimalTraitValuePair<DogTrait>> animalTraitValuePairs)
: base(i, name, animalTraitValuePairs)
{
}
public static Dog Fido = new Dog(1, "Fido", new[] {
new AnimalTraitValuePair<DogTrait>(DogTrait.Color, "Black"),
new AnimalTraitValuePair<DogTrait>(DogTrait.Size, "Medium"),
});
}
Output:
Fido's traits:
[Color, Black]
[Size, Medium]
You have a constraint on AnimalTraitValuePair
public struct AnimalTraitValuePair<TAnimalTrait>
where TAnimalTrait : AnimalTrait<TAnimalTrait>
When you use it you are passing in a TAnimal with Animal constraint
public abstract class Animal<TAnimal, TAnimalTrait>
: IEnumerable<AnimalTraitValuePair<TAnimal>>
where TAnimal : Animal<TAnimal, TAnimalTrait>
where TAnimalTrait : AnimalTrait<TAnimalTrait>
If you change it to the following:
public abstract class Animal<TAnimal, TAnimalTrait>
: IEnumerable<AnimalTraitValuePair<TAnimalTrait>>
where TAnimal : Animal<TAnimal, TAnimalTrait>
where TAnimalTrait : AnimalTrait<TAnimalTrait>
You will get a error stating that
Enumeration<AnimalTrait<TAnimalTrait>>.Value is inaccessable due to its protection level.
This occurs because your Animal class doesn't derive from Enumeration<AnimalTraitValuePair<TAnimalTrait>>
Honestly, being that IList<T> is a generic implementation of IEnumerable<T>, if you want a simple implementation that accomplishes the same goal, I'd just do the following:
public class Animal
{
private IList<AnimalTrait> _traits;
public Animal(IList<AnimalTrait> traits)
{
_traits = traits;
}
public IEnumerable<AnimalTrait> Traits{get{return _traits;}}
}
public class AnimalTrait
{
public int Value{get;set;}
public string DisplayName{get;set;}
}
I'd like to implement abstract factory design pattern. I add this snippet :
public class Class1
{
static Ete _ete;
static Hiver _hiver;
public static void Main(Clothes cl)
{
_ete = cl.CreateEteClothes();
_hiver = cl.CreateHiverClothes();
Console.WriteLine(_ete.GetMarque());
Console.ReadKey();
Console.WriteLine(_hiver.GetMarque());
Console.ReadKey();
}
}
public abstract class Clothes
{
public abstract Ete CreateEteClothes();
public abstract Hiver CreateHiverClothes();
}
public abstract class ItalianFactory: Clothes
{
public override Ete CreateEteClothes()
{
return new TShirtJuve();
}
public override Hiver CreateHiverClothes()
{
return new PullJuve();
}
}
public abstract class FrenchFactory : Clothes
{
public override Ete CreateEteClothes()
{
return new TShirtPsg();
}
public override Hiver CreateHiverClothes()
{
return new PullPsg();
}
}
public abstract class TunisianFactory : Clothes
{
public override Ete CreateEteClothes()
{
return new TShirtCa();
}
public override Hiver CreateHiverClothes()
{
return new PullCa();
}
}
public abstract class Ete
{
public abstract string GetMarque();
}
public abstract class Hiver
{
public abstract string GetMarque();
}
public class TShirtJuve: Ete
{
public override string GetMarque()
{
return "Juventus T shirt";
}
}
public class TShirtPsg : Ete
{
public override string GetMarque()
{
return "PSG T shirt";
}
}
public class TShirtCa : Ete
{
public override string GetMarque()
{
return "club africain T shirt";
}
}
public class PullJuve : Hiver
{
public override string GetMarque()
{
return "Juventus Pull";
}
}
public class PullPsg : Hiver
{
public override string GetMarque()
{
return "PSg Pull";
}
}
public class PullCa : Hiver
{
public override string GetMarque()
{
return "Club africain Pull";
}
}
I'd like to test this implementation, but I get an exception indicates that the signature of main method is not acceptable.
So How can I fix my code to test this design pattern implementation?
You have public static void Main(Clothes cl)
This should be static void Main(string[] args) as this is the entry point for the application and there can be only one entry point. See the .NET documentation for more info.
A method's signature usually consists of the methods name, return type, and parameters. Your application is expecting the correct signature for the Main method, hence it's giving you this exception.
is there a way to override a variable in a subclass, but also change the type to be a subclass of that type.
ie.
public class BaseClass
{
public BaseClass() { }
protected virtual MyBase WorkField { get { return new MyBase(); } }
public int WorkProperty
{
get { return WorkField.Value; }
}
}
public class DerivedClass : BaseClass
{
public DerivedClass():base() { }
/* I get an error here saying that WorkField needs to be MyBase type*/
protected override MyExtend WorkField
{
get
{
return new MyExtend();
}
}
//public new int WorkProperty
//{
// get { return 0; }
//}
}
public class MyBase
{
public int Value = 1;
}
public class MyExtend : MyBase
{
public int value = 20;
}
is there a way to do similar to this, but valid?
so i can have a superClass that does task on MyBase, and then have a subclass that does things on the MyEntend version of it.
without casting it everytime i use it.
There is no reason to change the signature in this case. Just return the derived type:
public class DerivedClass : BaseClass
{
public DerivedClass():base() { }
protected override MyBase WorkField
{
get
{
return new MyExtend();
}
}
//public new int WorkProperty
//{
// get { return 0; }
//}
}
The polymorphic behavior of your subclass will allow you to return it.
For overriding the signature should be of the base base method.
public class BaseClass<T> where T : MyBase, new()
{
public BaseClass() { }
protected virtual T WorkField { get { return new T(); } }
public int WorkProperty { get { return WorkField.Value; } }
}
public class DerivedClass : BaseClass<MyBase>
{
public DerivedClass() : base() { }
// same error occurs as base property is of type "MyBase"
protected override MyExtend WorkField { get { return new MyExtend();
} }
//public new int WorkProperty
//{
// get { return 0; }
//}
}
public class BaseClass<T> where T: MyBase, new()
{
public BaseClass() { }
protected virtual T WorkField { get { return new T(); } }
public int WorkProperty { get { return WorkField.Value; } }
}
public class DerivedClass : BaseClass<MyExtend>
{
public DerivedClass() : base() { }
protected override MyExtend WorkField { get { return new MyExtend(); } }
//public new int WorkProperty
//{
// get { return 0; }
//}
}
public class MyBase
{
public MyBase()
{
}
public int Value = 1;
}
public class MyExtend : MyBase
{
public int value = 20;
}