I would like to get all of the properties contained in a class whose types inherit from a certain abstract and generic class.
public abstract class foo<T> { }
public class fooInt_Indexed : foo<int> { }
public class fooInt_Not_Indexed : foo<int> { }
public class fooString_Compressed : foo<string> { }
public class fooString_Indexed : foo<string> { }
public class fooFloat : foo<float> { }
public abstract class bar
{
}
public class foobar : bar
{
public fooInt_Indexed value { get; set; }
public fooInt_Not_Indexed someOtherValue { get; set; }
public fooFloat someFloat { get; set; }
public otherData<int> {get; set; }
}
public class barChecker<T> where T : bar
{
public List<PropertyInfo> fooprops = new List<PropertyInfo>();
public static barChecker<T> Generator()
{
var #new = new barChecker<T>();
foreach (var item in typeof(T).GetProperties())
{
if (item.PropertyType is somesortof(foo<>)) #new.fooprops.Add(item);
}
return #new;
}
What do I need to put inside the barChecker<T> class code to make its fooprops list contain the property infos of "value","someOtherValue" and "someFloat" when generated as a barChecker<foobar> ?
Here's an extension method to System.Type that will answer this and similar questions about inheritance:
public static class TypeExtensions
{
public static bool InheritsFrom(this Type t, Type baseType)
{
if (t.BaseType == null)
{
return false;
}
else if (t == baseType)
{
return true;
}
else if (t.BaseType.IsGenericType && t.BaseType.GetGenericTypeDefinition().InheritsFrom(baseType))
{
return true;
}
else if (t.BaseType.InheritsFrom(baseType))
{
return true;
}
return false;
}
public static bool InheritsFrom<TBaseType>(this Type t)
=> t.InheritsFrom(typeof(TBaseType));
}
This here:
item.PropertyType is somesortof(foo<>)
Has to be replaced with
typeof(YourType).IsAssignableFrom(item.PropertyType)
The 'is' operator is only for real object instances, not if you already have a Type-Reference.
So in your case 'YourType' is typeof(barchecker< foobar >) ?
I have the following class that implements dependency injection for ISecurityRepository:
public class SecurityService : BaseService
{
ISecurityRepository _securityRepo = null;
public SecurityService(ISecurityRepository securityRepo)
{
_securityRepo = securityRepo;
}
}
Then I have the SecurityRepository class as follows:
public class SecurityRepository : BaseRepository, ISecurityRepository
{
public bool ValidateLogin(string userName, string password)
{
return true;
}
}
Then BaseRepository class:
public abstract class BaseRepository
{
private string _customString = null;
public string CustomString{
get {
return _customString ;
}
set
{
value = _customString ;
}
}
}
What I need is to set CustomString on BaseRepository class value from SecurityService class. Something maybe like this:
public class SecurityService : BaseService
{
ISecurityRepository _securityRepo = null;
public SecurityService(ISecurityRepository securityRepo)
{
_securityRepo = securityRepo;
// something like this or better way
_securityRepo.CustomString = "ABCD";
}
}
The idea is that within SecurityRepository class I can access CustomString value.
I have below object model with simple inheritance:
public class RuntimeApiManagerBase
{
}
public class CatalogRuntimeApiManagerBase : RuntimeApiManagerBase
{
public void Method1()
{
}
}
public class DocumentRuntimeApiManagerBase : RuntimeApiManagerBase
{
public void Method2()
{
}
public void Method3()
{
}
}
public class BaseObject
{
public BaseObject(RuntimeApiManagerBase runtimeApiMgr)
{
RuntimeApiMgr = runtimeApiMgr;
}
public RuntimeApiManagerBase RuntimeApiMgr { get; set; }
}
public class Catalog : BaseObject
{
public Catalog() : base(new CatalogRuntimeApiManagerBase())
{
}
}
public class Document : BaseObject
{
public Document() : base(new DocumentRuntimeApiManagerBase())
{
}
}
Now, I want to access RuntimeApiMgr Property's Methods based on exactly derived type. However, it displays nothing which is logical:
Catalog c1 = new Catalog();
// c1.RuntimeApiMgr. => No Method1
Document d1 = new Document();
// d1.RuntimeApiMgr. => No Method2 and Method3
Is that possible using different structure like Generics or something else?
Thanks for your time.
Use generics:
public class BaseObject<T>
where T : RuntimeApiManagerBase
{
public BaseObject(T runtimeApiMgr)
{
RuntimeApiMgr = runtimeApiMgr;
}
public T RuntimeApiMgr { get; set; }
}
public class Catalog : BaseObject<CatalogRuntimeApiManagerBase>
{
public Catalog() : base(new CatalogRuntimeApiManagerBase())
{
}
}
public class Document : BaseObject<DocumentRuntimeApiManagerBase>
{
public Document() : base(new DocumentRuntimeApiManagerBase())
{
}
}
In that case your c1.RuntimeApiMgr will be of the type CatalogRuntimeApiManagerBase and will have Method1
You can use RuntimeApiManagerBase as generic and have a type constraint where T must be a subclass of RuntimeApiManagerBase
public class BaseObject<T> where T : RuntimeApiManagerBase
{
public BaseObject(T runtimeApiMgr)
{
RuntimeApiMgr = runtimeApiMgr;
}
public T RuntimeApiMgr { get; set; }
}
public class Catalog : BaseObject<CatalogRuntimeApiManagerBase>
{
public Catalog() : base(new CatalogRuntimeApiManagerBase())
{
}
}
public class Document : BaseObject<DocumentRuntimeApiManagerBase>
{
public Document() : base(new DocumentRuntimeApiManagerBase())
{
}
}
Catalog c1 = new Catalog();
c1.RuntimeApiMgr.Method1();
Document d1 = new Document();
d1.RuntimeApiMgr.Method2();
Alternative to solution with generics is an old fashioned approach with casting.
Maybe something like this:
Catalog c1 = new Catalog();
(c1.RuntimeApiMgr as CatalogRuntimeApiManagerBase).Method1();
Document d1 = new Document();
(d1.RuntimeApiMgr as DocumentRuntimeApiManagerBase).Method2();
Or create new properties with the same name in Caltalog and Document classes:
public class Catalog : BaseObject
{
public Catalog() : base(new CatalogRuntimeApiManagerBase())
{
}
public new CatalogRuntimeApiManagerBase RuntimeApiMgr { get; set; }
}
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'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();
}
}