简体   繁体   English

如何在泛型 class 中访问 T 类型的 static 属性?

[英]How can I access a static property of type T in a generic class?

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 from TestClass).我正在尝试完成以下场景,即通用 TestClassWrapper 将能够访问它所组成的类的 static 个属性(它们都将派生自 TestClass)。 Something like:就像是:

public class TestClass
{
    public static int x = 5;
}

public class TestClassWrapper<T> where T : TestClass
{
    public int test()
    {
        return T.x;
    }
}

Gives the error:给出错误:

'T' is a 'type parameter', which is not valid in the given context. “T”是“类型参数”,在给定上下文中无效。

Any suggestions?有什么建议么?

You can't, basically, at least not without reflection.你不能,基本上,至少不能没有反思。

One option is to put a delegate in your constructor so that whoever creates an instance can specify how to get at it:一种选择是在构造函数中放置一个委托,以便创建实例的人可以指定如何获取它:

var wrapper = new TestClassWrapper<TestClass>(() => TestClass.x);

You could do it with reflection if necessary:如有必要,您可以通过反射来实现:

public class TestClassWrapper<T> where T : TestClass
{
    private static readonly FieldInfo field = typeof(T).GetField("x");

    public int test()
    {
        return (int) field.GetValue(null);
    }
}

(Add appropriate binding flags if necessary.) (如有必要,添加适当的绑定标志。)

This isn't great, but at least you only need to look up the field once...这不是很好,但至少你只需要查看一次字段......

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.即使在一个重要的例子中,你也不能覆盖一个静态字段,所以总是从你已知的基类中调用它。

为什么不直接返回TestClass.x

T is a type, not parameter or variable so you cannot pick any value from any members. T 是一种类型,而不是参数或变量,因此您不能从任何成员中选取任何值。 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; }
}

Another solution is to simply not make it static, and work with the new() constraint on T to instantiate the object.另一个解决方案是简单地使其成为静态,并使用 T 上的new()约束来实例化对象。 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;实际上,您可以在 TestClassWrapper 上将其更改为public static Int32 X并简单地将其作为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.尽管因为无论代码调用它都必须给参数 T 提供相同的约束,所以此时包装类是非常不必要的,因为调用代码本身也可以只执行new T().X而不必打扰包装器。

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> ).例如, abstract class SuperClass<T> where T : SuperClass<T>, new()可以在其静态函数中实例化和返回类型 T,有效地允许您创建适应子类的可继承静态函数(这将然后需要定义为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.通过在超类上定义protected abstract函数/属性,您可以创建在任何继承对象上应用相同逻辑的函数,但根据这些抽象的实现为该子类定制。 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.这是一个相当简化的示例,但正如您所见,该系统允许在子类上调用来自父类的静态函数,以返回子类的对象。

cjk and Haris Hasan have the most-correct answers to the question as asked. cjkHaris Hasan对问题的回答最正确。 However in this comment the OP implies that he is after something else not quite possible in C#: a way to define a contract for a static member in a derived class.然而,在这个评论中,OP 暗示他在 C# 中追求其他不太可能的东西:一种在派生的 class 中为 static 成员定义合同的方法。

There isn't a way to strictly define this, but it is possible to set up a pattern that may be implied by a base class (or interface);没有办法严格定义它,但可以设置一个模式,该模式可能由基数 class(或接口)暗示; eg:例如:

public class TestClass
{
    private static int x;

    public virtual int StaticX => x;
}

or if not intended to be used directly或者如果不打算直接使用

public abstract class AbstractTestClass
{
    public abstract int StaticX {get;}
}

or (my preference in this contrived example)或者(我在这个人为的例子中的偏好)

public interface ITest
{
    int StaticX {get;}
}

Elsewhere, this pattern of a StaticXxx member may be (loosely) associated with implementations that should back the member with static fields (as in TestClass above).在其他地方, StaticXxx成员的这种模式可能(松散地)与应该使用 static 字段(如上面的TestClass中)支持成员的实现相关联。

What's kind of fun is that this can be (re)exposed as static by the generic wrapper, because generic statics are isolated to each type used.有趣的是,通用包装器可以将其(重新)公开为 static,因为通用静态与所使用的每种类型都是隔离的。

public class TestClassWrapper<T> where T : ITest, new()
{
    private readonly static T testInstance = new T();

    public static int test() => testInstance.x;
}

This uses a new() condition, but an associated static, generic factory pattern for creating ITest (or TestClass or AbstractTestClass ) instances may also be used.这使用new()条件,但也可以使用关联的 static 通用工厂模式来创建ITest (或TestClassAbstractTestClass )实例。 However this may not be feasible if you can't have long-lived instances of the class.但是,如果您没有 class 的长期实例,这可能不可行。

In this situation you assume that T is a subclass of TestClass.在这种情况下,您假设 T 是 TestClass 的子类。 Subclasses of TestClass will not have the static int x. TestClass 的子类将没有静态 int x。

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:假设该字段真正与特定的T ,您还可以使用反射:

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

but I don't recommend it.但我不推荐它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 当T是具有未知参数的泛型类时,如何访问类型T的对象上的属性? - How can I access property on object of type T, when T is a generic class with unknown parameter? 为什么我不能在静态类中访问公共属性字段 - Why can't I access public property field in static class 如何访问返回通用类型的类中的方法 - How can I access to the method in class that returns a Generic Type 我如何在非泛型静态类的多个方法中使用同一泛型类型 - How can I use the same generic type in multiple methods in a non-generic static class 我无法访问 C# 中通用基础 class 的 static 属性或字段 - I can't get access to static properties or fields of my generic base class in C# 无法访问我在泛型方法中用作类型参数的 class 的基数 class 的属性 - Can't access properties of the base class of the class I am using as the type argument in a generic method 如何使用反射调用泛型类的静态属性? - How do I call a static property of a generic class with reflection? 如何将事件处理程序添加到泛型类型 T 的静态类事件? - How to add an event handler to a static class event of a generic type T? 当属性位于基类中时,如何访问子类中的静态属性? - How can I access a static property in a subclass when the property is located in a base class? 我如何通过C#访问泛型类中的动态类属性? - How i access dynamic class property in generic class by c#?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM