Access static constant of a subclass from the base class - c#

I have an Animal base class and every subclass needs a static string ID for identification purposes.
So I might have:
public class Dog : Animal {
public static readonly string ID = "dog";
}
I do this because I frequently need to use Dog.ID throughout my app - in places where I don't yet have an instance.
However, I also need to access this when I have an instance, but I only want to put something like GetId() in the base class:
public class Animal {
public string GetId() {
return ID;
}
}
The problem is, Animal would not have access to the static ID field in the children.
Is there a way to do this that I've overlooked?

What about an abstract method?
public class Dog : Animal
{
public static readonly string ID = "dog";
public override string GetId()
{
return ID;
}
}
public abstract class Animal
{
public abstract string GetId();
}
or virtual
public class Animal
{
public virtual string GetId()
{
return null;
}
}

Ugly... But you could use reflection:
FieldInfo id = GetType().GetField("ID", BindingFlags.Public | BindingFlags.Static);
return id.GetValue(null);

If this is a static, set-once identifier, it seems like you should use an attribute instead of a static field or property:
public class AnimalIdAttribute : Attribute
{
public AnimalIdAttribute(string id)
{
Id = id;
}
public string Id { get; }
}
public class Animal
{
public string Id => this.GetCustomAttribute<AnimalIdAttribute>(true)?.Id;
}
[AnimalId("dog")]
public class Dog : Animal
{
}
Also, if any animal should provide an Id, your Animal class should be an abstract class which should also define an abstract Id property:
public abstract class Animal
{
// Now you can access Id property implementation
// from Animal
public abstract string Id { get; }
}
public class Dog : Animal
{
public override string Id { get; } = "dog";
}

Or, you can do something like this:
public class Animal
{
public static string Id;
public virtual string GetId()
{
return Id;
}
}
public class Dog : Animal
{
public new static readonly string Id = "dog";
public override string GetId()
{
return Id;
}
}
This gives you ability to call Id from Class or an instance.

Implement explicit interface like this
public class Animal : IType
{
private static string _ID = "Animal";
string IType.ID
{
get
{
return getID();
}
}
public virtual string getID()
{
return _ID;
}
}
public class Dog : Animal, IType
{
public static readonly string _dogID = "dog";
string IType.ID
{
get
{
return _dogID;
}
}
public override string getID()
{
return _dogID;
}
}
....
// usage
Animal a = new Animal();
Animal d = new Dog();
Console.WriteLine(a.getID());
Console.WriteLine(d.getID());

If you agree to an assumption that ID equals to the type name, you can use this approach. It lets you define and inherit ID property in the base class.
Though I agree this might look quite strange at first sight.
public class Animal<T> where T : Animal<T>
{
public static readonly string ID = typeof(T).Name;
}
public class Dog : Animal<Dog>
{
}
public class Cat : Animal<Cat>
{
}
Expression Cat.ID will return Cat, and Dog.ID will return Dog.

Related

How access to abstract property from abstract that inherits interface?

I am not able to access a virtual property (IsNameAPalindrome) of an abstract class (PetBase ) having interface(IPet) inherited.
public interface IPet
{
string Name { get; set; }
}
public abstract class PetBase : IPet
{
public abstract string Name { get; set; }
public virtual bool IsNameAPalindrome
{
get
{
return (Name.Equals(string.Join("", Name.Reverse())));
}
}
}
The derived classes inherit the abstract class (PetBase)
public class Bird : PetBase
{
public override string Name { get; set; }
}
public class Cat : PetBase
{
public override string Name { get; set; }
}
public class Dog : PetBase
{
public override string Name { get; set; }
}
public class House : List<IPet>
{
}
Now when I try to access the property(IsNameAPalindrome) while looping through house object, it is not accessible
class Program
{
static void Main(string[] args)
{
House house = BuildHouse();
Print(house);
}
static void Print(House house)
{
// TODO: Print the contents of the house similar to the below.
// Feel free to change or improve upon the table as you see fit.
//Name Palindrome
//Gracie False
//Patches False
//Izzi True
//Missy False
Console.WriteLine("Name Palindrome");
foreach (var item in house)
{
Console.WriteLine( item.Name);
}
}
static House BuildHouse()
{
House house = new House();
house.Add(new Cat()
{
Name = "Gracie"
});
house.Add(new Cat()
{
Name = "Patches"
});
house.Add(new Bird()
{
Name = "Izzi"
});
house.Add(new Dog()
{
Name = "Missy"
});
return house;
}
}
You define House as List<IPet>, meaning the compiler will see each list element as the type IPet, which does not have a property IsNameAPalindrome.
If it makes logical sense for IsNameAPalindrome to be part of that interface contract, the simple solution is to add it:
public interface IPet
{
string Name { get; set; }
bool IsNameAPalindrome { get; }
}
If that does not make sense to you (and it may not, given that palendromes aren't closely linked to the concept of being a pet), you can:
Cast each IPet to PetBase to access that property
Implement a new interface e.g. IPalendrome, have PetBase also implement that interface, and cast to that interface to access the method.
Changes to the code for
First option
Console.WriteLine( ((PetBase)item).IsNameAPalindrome);
Second option
public interface IPalendrome
{
bool IsNameAPalindrome { get; }
}
public abstract class PetBase : IPet, IPalendrome
{
...
}
Console.WriteLine( ((IPalendrome)item).IsNameAPalindrome);

Get a Static property from a class generic, where Interface contains the property name

When you have a function:
public interface IHasName
{
static string Name { get; }
}
//class{
public static string GetName<T>() where T : IHasName
{
return T.Name;
}
//}
This is not working, only when I change the static to public and I create a new T().
The usage have to be like:
public class Model: IHasName
{
public static string Name => "Niek";
}
var name = GetName<Model>();
Do you have the solution that sill use a static property through a Generic.
Thanks in advance!
This is available as a preview feature in .NET 6, and will probably be properly released in .NET 7:
public interface IHasName
{
public static abstract string Name { get; }
}
public class Model : IHasName
{
public static string Name => "Foo";
}
class Foo
{
public static string GetName<T>() where T : IHasName
{
return T.Name;
}
}
See it on dotnetfiddle.net.

C# generic method that takes multiple classes

I want to create a generic method like this one:
public static List<T> Filter(this List<T> list, string search) where T : class
{
return list.Where(t => t.Name.FormatSearch().Contains(search)).ToList();
}
And to be albe to call this method on different classes and get the same result because both classes have mostly the same attributes.
class A {
public string Name;
}
class B {
public string Name;
}
var a = new List<A>();
var b = new List<B>();
a.Filter();
b.Filter();
I expect the filter method to work the same way for both A and B. What Am I'm missing in the first method?
One way to do that is to create Interface IName and declare Name Property there.
A and B should implement IName.
Write T parameter constraint as follows where T : IName
After that you will avoid red line under t.Name...
Try following .
using System.Collections.Generic;
using System.Linq;
namespace TestField
{
class Program
{
private static void Main(string[] args)
{
var a = new List<A>();
var b = new List<B>();
a.Filter("string");
b.Filter("string");
}
}
public static class Extensions
{
public static List<T> Filter<T>(this IEnumerable<T> list, string search)
where T : IName
=> list.Where(t => t.Name.Contains(search)).ToList();
}
public interface IName
{
string Name { get; set; }
}
public class A : IName
{
public string Name { get; set; }
}
public class B : IName
{
public string Name { get; set; }
}
}
The answer was given by #tchelidze this is what I wanted to do:
public interface IName
{
string Name { set; get; }
}
class A : IName {
public string Name
}
class B : IName {
public string Name
}
public static List<T> Filter<T>(this List<T> list, string search) where T : IName
{
return list.Where(t => t.Name.FormatSearch().Contains(search)).ToList();
}

Inheritance interface as return type - Cannot convert expression

I have the following
public interface IAwesomeInterface
{
string Prop1 {get; set;}
string Prop2 {get; set;}
List<SomeObject> GetObjects();
}
public abstract class AbstractObject : IAwesomeInterface
{
public string Prop1 {get; set;}
public string Prop2 {get; set;}
public abstract List<SomeObject> GetObjects();
}
public class ConcreteObject1 : AbstractObject
{
public List<SomeObject> GetObjects()
{
return new List<SomeObject>();
}
}
public class ConcreteObject2 : AbstractObject
{
public List<SomeObject> GetObject()
{
//do some other stuff
return new List<SomeObject>();
}
}
and an implementation of:
public class ObjectFactory
{
public IAwesomeInterface GetObject()
{
return new ConcreteObject1();
}
}
I am getting an error that "Cannot convert expression type ConcreteObject1 to return type IAwesomeInterface"
Since ConcreteObject1 inherits from AbstractObject, doesn't that mean that it implements IAwesomeInterface and should be an acceptable return value?
Your code throws also another error, which is the reason the second one exists:
'ConcreteObject1' does not implement inherited abstract member 'AbstractObject.GetObjects()'
Fix this one, and the one you've quoted will go away too. To do that, add override next to GetObjects() method in both ConcreteObject1 and ConcreteObject2:
public class ConcreteObject1 : AbstractObject
{
public override List<SomeObject> GetObjects()
{
return new List<SomeObject>();
}
}
public class ConcreteObject2 : AbstractObject
{
public override List<SomeObject> GetObjects()
{
//do some other stuff
return new List<SomeObject>();
}
}
PS. Your code had a typo in GetObjects method name. You missed s at the end of method name.

How to Protect Base Field's Public/Private

If i have a ClassA
public class ClassA
{
public string name;
}
Where Attribute Name is Public ,and it can be modified from Anywhere .
Than i have a ClassB
public class ClassB : ClassA
{
private string name;//But it's not Woking ,name is still public
}
...which Inherit's ClassA ,but i need at ClassB to make name as Private Field.
So if i create an Object of Type ClassB than ClassB.name cannot be modified .
just don't publish the field but accessors:
public class ClassA
{
private string _name;
public string Name { get { return _name; } protected set { _name = value; } }
}
public class ClassB : ClassA
{
/* nothing left to do - you can set Name in here but not from outside */
}
This is not possible. You can not change visibility of base class's field.
Assuming you cannot change A, do not use inheritance, but aggregation and delegation:
public class A {
public string name;
public int f() { return 42; }
}
public class B {
private A a;
public int f() { return a.f(); }
public string getName() { return a.name; }
}
Carsten Konig's method is a good way, and here is an alternative.
public class ClassA {
public virtual string Name {
get;
private set;
}
}
public class ClassB : ClassA {
public override string Name {
get {
return base.Name;
}
}
}
Hm. There is a pair of tricks for this. But none of them is what you really want. One is:
public class ClassA
{
protected string name;
public string Name { get { return name; } public set { name = value; } }
}
public class ClassB : ClassA
{
public new string Name { get { return base.name; } }
}
If you don't have control over ClassA, you can do this:
void Main()
{
var b = new ClassB();
var a = (ClassA)b;
a.name = "hello";
b.PrintName();
}
class ClassA {
public string name;
}
class ClassB : ClassA {
private new string name;
public void PrintName() {
Console.WriteLine(base.name);
}
}

Categories