我正在尝试完成以下场景:通用TestClassWrapper将能够访问它所构成的类的静态属性(它们都将从TestClass派生)。类似的东西:
public class TestClass
{
public static int x = 5;
}
public class TestClassWrapper<T> where T : TestClass
{
public int test()
{
return T.x;
}
}
给出错误:'T' is a 'type parameter', which is not valid in the given context.
有什么建议吗?
答案 0 :(得分:26)
基本上,你不能没有反思。
一个选项是在您的构造函数中放置一个委托,以便创建实例的人可以指定如何获取它:
var wrapper = new TestClassWrapper<TestClass>(() => TestClass.x);
如果需要,你可以用反射来做到这一点:
public class TestClassWrapper<T> where T : TestClass
{
private static readonly FieldInfo field = typeof(T).GetField("x");
public int test()
{
return (int) field.GetValue(null);
}
}
(如有必要,添加适当的绑定标志。)
这不是很好,但至少你只需要查看一次......
答案 1 :(得分:7)
当然你可以写下这个:
public int test()
{
return TestClass.x;
}
即使在一个非常重要的例子中,你也不能覆盖静态字段,因此总是会从已知的基类中调用它。
答案 2 :(得分:1)
为什么不返回TestClass.x
?
答案 3 :(得分:0)
在这种情况下,您假设T是TestClass的子类。 TestClass的子类不具有静态int x。
答案 4 :(得分:0)
泛型不支持任何与静态成员相关的内容,因此不起作用。我的建议是:不要让它静止。假设该字段真正与特定T
相关,您也可以使用反射:
return (int) typeof(T).GetField("x").GetValue(null);
但我不推荐它。
答案 5 :(得分:0)
T是一种类型,而不是参数或变量,因此您无法从任何成员中选择任何值。这是一个示例代码。
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; }
}
答案 6 :(得分:0)
另一种解决方案是简单地不使其成为静态,并使用T上的new()
约束来实例化对象。然后,您可以使用接口,并且包装器可以从实现该接口的任何类中获取该属性:
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; }
}
}
实际上,您可以将其更改为TestClassWrapper上的public static Int32 X
,然后将其作为Int32 fetchedX = XExposerWrapper<TestClass>.X;
虽然无论代码调用什么,都必须给参数T赋予相同的约束,但此时包装类是非常不必要的,因为调用代码本身也可以只执行new T().X
而不用打包器
但是,有一些有趣的继承模型,这种结构很有用。例如,abstract class SuperClass<T> where T : SuperClass<T>, new()
可以在其静态函数中实例化并返回类型T,从而有效地允许您创建适应子类的可继承静态函数(然后需要将其定义为class ChildClass : SuperClass<ChildClass>
) 。通过在超类上定义protected abstract
函数/属性,您可以创建在任何继承对象上应用相同逻辑的函数,但根据这些抽象的实现自定义到该子类。我将它用于数据库类,其中表名和fetch查询由子类实现。由于属性受到保护,因此它们也不会暴露。