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
虽然无论代码调用什么,都必须给参数T赋予相同的约束,但此时包装类是非常不必要的,因为调用代码本身也可以只执行new T().X
并且不需要使用包装器。
不过,有一些有趣的inheritance模型,这种结构很有用。 例如, abstract class SuperClass
可以在其静态函数中实例化并返回类型T,从而有效地允许您创建适应子类的可inheritance静态函数(这将是然后需要定义为class ChildClass : SuperClass
)。 通过在超类上定义protected abstract
函数/属性,您可以创建在任何inheritance对象上应用相同逻辑的函数,但根据这些抽象的实现自定义到该子类。 我将它用于数据库类,其中表名和fetch查询由子类实现。 由于属性受到保护,因此它们也不会暴露。