C# accessing a static property of type T in a generic class

前端 未结 7 1517
后悔当初
后悔当初 2020-12-16 09:30

I am trying to accomplish the following scenario that the generic TestClassWrapper will be able to access static properties of classes it is made of (they will all derive fr

7条回答
  •  甜味超标
    2020-12-16 10:03

    Another solution is to simply not make it static, and work with the new() constraint on T to instantiate the object. Then you can work with an interface, and the wrapper can get the property out of any class that implements that interface:

    public interface XExposer
    {
        Int32 X { get; }
    }
    
    public class TestClass : XExposer
    {
        public Int32 X { get { return 5;} }
    }
    
    public class XExposerWrapper where T : XExposer, new()
    {
        public Int32 X
        {
            get { return new T().X; }
        }
    }
    

    In fact, you can change that to public static Int32 X on the TestClassWrapper and simply get it out as Int32 fetchedX = XExposerWrapper.X;

    Though since whatever code calls this will have to give the parameter T those same constraints, the wrapper class is pretty unnecessary at this point, since that calling code itself could also just execute new T().X and not bother with the wrapper.

    Still, there are some interesting inheritance models where this kind of structure is useful. For example, an abstract class SuperClass where T : SuperClass, new() can both instantiate and return type T in its static functions, effectively allowing you to make inheritable static functions that adapt to the child classes (which would then need to be defined as class ChildClass : SuperClass). By defining protected abstract functions / properties on the superclass, you can make functions that apply the same logic on any inherited object, but customized to that subclass according to its implementations of these abstracts. I use this for database classes where the table name and fetch query are implemented by the child class. Since the properties are protected, they are never exposed, either.

    For example, on database classes, where the actual fetching logic is put in one central abstract class:

    public abstract class DbClass where T : DbClass, new()
    {
        protected abstract String FetchQuery { get; }
    
        protected abstract void Initialize(DatabaseRecord row);
    
        public static T FetchObject(DatabaseSession dbSession, Int32 key)
        {
            T obj = new T();
            DatabaseRecord record = dbSession.RetrieveRecord(obj.FetchQuery, key);
            obj.Initialize(row);
            return obj;
        }
    }
    

    And the implementation:

    public class User : DbClass
    {
        public Int32 Key { get; private set;}
        public String FirstName { get; set;}
        public String LastName { get; set;}
    
        protected override String FetchQuery
        { get { return "SELECT * FROM USER WHERE KEY = {0}";} }
    
        protected override void Initialize(DatabaseRecord row)
        {
            this.Key = DatabaseSession.SafeGetInt(row.GetField("KEY"));
            this.FirstName = DatabaseSession.SafeGetString(row.GetField("FIRST_NAME"));
            this.LastName = DatabaseSession.SafeGetString(row.GetField("LAST_NAME"));
        }
    }
    

    This can be used as:

    User usr = User.FetchObject(dbSession, userKey);
    

    This is a rather simplified example, but as you see, this system allows a static function from the parent class to be called on the child class, to return an object of the child class.

提交回复
热议问题