Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access const with generics C#

I have the following base class:

public class Base
{
    public string LogicalName { get; set; }
    public int NumberOfChars { get; set; }

    public Base()
    {

    }

    public Base(string logicalName, int numberOfChars)
    {
        LogicalName = logicalName;
        NumberOfChars = numberOfChars;
    }  
}

and the following derived classes:

public class Derived1 : Base
{
    public const string EntityLogicalName = "Name1";
    public const int EntityNumberOfChars = 30;

    public Derived1() : base(EntityLogicalName, EntityNumberOfChars)
    {

    }
}

public class Derived2 : Base
{
    public const string EntityLogicalName = "Name2";
    public const int EntityNumberOfChars = 50;

    public Derived2()
        : base(EntityLogicalName, EntityNumberOfChars)
    {

    }
}

and I also have this function that is provided by a service:

public IEnumerable<T> GetEntities<T>(string entityName, int numberOfChars) where T : Base
{
    //Some code to get the entities
}

My problem is how can I call this function generically? I want to call it with something that looks like this:

public void TestEntities<T>() where T : Base
{
    var entities = GetEntities<T>(T.EntityLogicalName, T.EntityNumberOfChars);

    //some other code to test the entities
}

This of course doesn't work because at this point T is not known. How can I accomplish something similar to this? EntityLogicalName and EntityNumberOfChars are characteristics that all Base derived classes have and they never change for each derived class. Can I get them from the Base class without instantiating objects or some other way that I am not seeing?

like image 544
budahead Avatar asked Aug 11 '15 17:08

budahead


1 Answers

Replace constants with getter abstract properties

public abstract class Base
{
   public abstract string LogicalName { get; }
   public abstract int NumberOfChars { get; }

   public Base()
   {

   } 
}


public class Derived1 : Base
{
   public string LogicalName { get { return "Name1"; } } 
   public int NumberOfChars { get { return 30; } } 

   public Derived1() : base()
   {

    }
}

Also, you will be able to put some logic into overriden getter, e.g. :

...
public string LogicalName { get { return this.EntityMap.Name; } } 
...

UPDATE: The fact that you do not want to instantiate object from class but want to be able to get that string in a strongly typed manner can be handled in one more way. It is totally separate from answer above ( Since you can't override static props in c#). Consider the following code. We are adding one more class here, but LocatorInner can be a member of BaseClass. We are using this approach a lot in several existing apps.:

public class Locator
{
    public static class LocatorInner<T> where T : BaseClass
    {
        public static string Name { get; set; }
    }

    public static string GetName<T>() where T : BaseClass
    {
        return LocatorInner<T>.Name;
    }

    public static void SetName<T>(string name) where T : BaseClass
    {
        LocatorInner<T>.Name = name;
    }
}

public class BaseClass
{

}

public class DerivedClass: BaseClass
{
    static DerivedClass()
    {
        Locator.LocatorInner<DerivedClass>.Name = "me";
    }
}

public class TestClass<T> where T : BaseClass
{
    public void Method()
    {
        var name = Locator.GetName<T>();
    }
}
like image 137
vittore Avatar answered Oct 24 '22 10:10

vittore