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

前端 未结 7 1474
后悔当初
后悔当初 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 09:42

    In this situation you assume that T is a subclass of TestClass. Subclasses of TestClass will not have the static int x.

    0 讨论(0)
  • 2020-12-16 09:48

    Surely you can just write this:

    public int test() 
    { 
        return TestClass.x; 
    } 
    

    Even in a nontrivial example, you can't override a static field so will always call it from your known base class.

    0 讨论(0)
  • 2020-12-16 09:58

    T is a type, not parameter or variable so you cannot pick any value from any members. Here is a sample code.

    public class UrlRecordService
    {
        public virtual void SaveSlug<T>(T entity) where T : ISlugSupport
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
    
            int entityId = entity.Id;
            string entityName = typeof(T).Name;
        }
    }
    
    
    public interface ISlugSupport
    {
        int Id { get; set; }
    }
    
    0 讨论(0)
  • 2020-12-16 10:00

    Generics do not support anything related to static members, so that won't work. My advice would be: don't make it static. Assuming the field genuinely relates to the specific T, you could also use reflection:

    return (int) typeof(T).GetField("x").GetValue(null);
    

    but I don't recommend it.

    0 讨论(0)
  • 2020-12-16 10:03

    Why not just return TestClass.x?

    0 讨论(0)
  • 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<T> 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<TestClass>.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<T> where T : SuperClass<T>, 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<ChildClass>). 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<T> where T : DbClass<T>, 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<User>
    {
        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.

    0 讨论(0)
提交回复
热议问题