C#在generics类中访问类型T的静态属性

我试图完成以下场景,通用TestClassWrapper将能够访问它所构成的类的静态属性(它们都将从TestClass派生)。 就像是:

public class TestClass { public static int x = 5; } public class TestClassWrapper where T : TestClass { public int test() { return Tx; } } 

给出错误: 'T' is a 'type parameter', which is not valid in the given context.

有什么建议?

基本上,你不能没有反思。

一种选择是将委托放在构造函数中,以便创建实例的人可以指定如何获取它:

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

如有必要,你可以用reflection做到这一点:

 public class TestClassWrapper where T : TestClass { private static readonly FieldInfo field = typeof(T).GetField("x"); public int test() { return (int) field.GetValue(null); } } 

(如有必要,添加适当的绑定标志。)

这不是很好,但至少你只需要查看一次……

当然你可以这样写:

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

即使在一个非常重要的示例中,您也无法覆盖静态字段,因此始终会从已知的基类中调用它。

为什么不返回TestClass.x

在这种情况下,您假设T是TestClass的子类。 TestClass的子类不具有静态int x。

generics不支持与静态成员相关的任何内容,因此不起作用。 我的建议是:不要让它静止。 假设该字段真正与特定T ,您还可以使用reflection:

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

但我不推荐它。

T是一个类型,而不是参数或变量,因此您无法从任何成员中选择任何值。 这是一个示例代码。

 public class UrlRecordService { public virtual void SaveSlug(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; } } 

另一种解决方案是简单地使其成为静态,并使用T上的new()约束来实例化对象。 然后,您可以使用接口,并且包装器可以从实现该接口的任何类中获取该属性:

 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; } } } 

实际上,您可以将它更改为TestClassWrapper上的public static Int32 X ,并将其作为Int32 fetchedX = XExposerWrapper.X;

虽然无论代码调用什么,都必须给参数T赋予相同的约束,但此时包装类是非常不必要的,因为调用代码本身也可以只执行new T().X并且不需要使用包装器。

不过,有一些有趣的inheritance模型,这种结构很有用。 例如, abstract class SuperClass where T : SuperClass, new()可以在其静态函数中实例化并返回类型T,从而有效地允许您创建适应子类的可inheritance静态函数(这将是然后需要定义为class ChildClass : SuperClass )。 通过在超类上定义protected abstract函数/属性,您可以创建在任何inheritance对象上应用相同逻辑的函数,但根据这些抽象的实现自定义到该子类。 我将它用于数据库类,其中表名和fetch查询由子类实现。 由于属性受到保护,因此它们也不会暴露。