如何获取抽象“const”的值使用反射的属性?
我有一个这样定义的类:
public abstract class Uniform<T>
{
public abstract string GlslType { get; }
...
}
然后有一个像这样定义的子类:
public class UniformInt : Uniform<int>
{
public override string GlslType
{
get { return "int"; }
}
}
然后在其他地方有一个看起来像这样的方法:
public static string GetCode<T>()
{
var sb = new StringBuilder();
var type = typeof(T);
sb.AppendFormat("struct {0} {{\n", type.Name);
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach(var f in fields)
{
sb.AppendFormat(" {0} {1};\n", f.FieldType.GetProperty("GlslType").GetValue(???), f.Name);
}
...
}
我在填写 ???
时遇到了麻烦。我相信 GetValue 需要一个对象的实例,但我并不关心它是什么实例,因为它们都返回相同的值。而且据我所知,不存在“公共抽象静态只读”值这样的东西,所以我必须使用属性。
那么我可以用什么来代替这些 ???
来返回“int”(假设其中一个字段是 UniformInt
)。
另一方面:如何将字段
限制为仅继承Uniform<>
的字段类型?
I've got a class defined like this:
public abstract class Uniform<T>
{
public abstract string GlslType { get; }
...
}
And then a subclass defined like this:
public class UniformInt : Uniform<int>
{
public override string GlslType
{
get { return "int"; }
}
}
And then a method somewhere else that looks like this:
public static string GetCode<T>()
{
var sb = new StringBuilder();
var type = typeof(T);
sb.AppendFormat("struct {0} {{\n", type.Name);
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach(var f in fields)
{
sb.AppendFormat(" {0} {1};\n", f.FieldType.GetProperty("GlslType").GetValue(???), f.Name);
}
...
}
I'm having trouble filling in the ???
s. I believe GetValue
expects an instance of the object, but I don't really care what instance it is because they all return the same value. And AFAIK there's no such thing as a public abstract static readonly
value, so I have to use properties.
So what can I put in place of those ???
s to get back "int" (assuming one the fields was a UniformInt
).
As a side: How can I limit fields
to only field types that inherit Uniform<>
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您需要一个 UniformInt 实例才能获取非静态属性的值:
或者如果您事先不知道
T
的类型:You need an instance of
UniformInt
in order to get the value of a non-static property:or if you don't know the type of
T
in advance:问题是,由于您的属性不是静态的,编译器不知道它们都返回相同的值。由于您的 UniformInt 未密封,其他用户可以继承它并覆盖 GlslType 以返回其他内容。然后,
UniformInt
和所有派生类都可以用于您的GetCode()
方法。静态方法确实是最好的选择。为了确保在所有类上实现它们(不能强制执行,因为静态方法不能是抽象的),我将编写一个简单的单元测试,它使用反射来加载从
Uniform继承的所有类。
并检查它们是否定义了静态属性。更新
当考虑属性如何提供帮助并经过一些实验后,我得出了以下结论。它肯定不会赢得选美比赛,但作为一种学习练习,它很有帮助;)
The problem is that since your property is not static the compiler doesn't know that they all return the same value. Since your
UniformInt
is not sealed, another user could inherit from it and overrideGlslType
to return something else. ThenUniformInt
and all derived classes could be used for yourGetCode<T>()
method.A static method would really be the best option. To make sure that you implement them on all classes (something you can't force because static methods can't be abstract) I would write a simple unit test that uses reflection to load all classes that inherit from
Uniform<T>
and check if they have the static property defined.UPDATE
When thinking about how Attributes could help and after some experimenting I came up with the following. It definitely won't win a beauty contest but as a learning exercise it was helpful ;)
GlslType 不是静态的,因此您需要一个对象引用才能访问它的值。抽象类中静态属性的主题已经被广泛讨论,即:
The
GlslType
is not static, so you need an object reference before you can access it's value. The subject of static properties in abstract classes has been covered extensively already, ie:解决方案 1
将静态方法添加到返回
GlslType
的所有派生类。不需要向基类添加任何内容。可以使用单元测试+反射来检查是否缺少实现。由 Wouter de Kort 建议。解决方案 2
更改
Uniform
以使GlslType
静态:将
UniformInt
更改为“覆盖”GlslType
,保留static 修饰符:用
null, null
填充???
:解决方案 3
使用 属性代替。类似于:
结论
所有这 3 个解决方案都非常相似,并且似乎具有相同的缺点(无法强制派生类来实现它)。通过方法 1 或 2 引发异常将有助于快速查找错误,或者使用方法 3,我可以通过修改我的
fields
条件来跳过没有该属性的类。Solution 1
Add static methods to all derived classes that return the
GlslType
. Nothing needs to be added to the base class. Can use unit testing + reflection to check for missing implementation. Suggested by Wouter de Kort.Solution 2
Change
Uniform<T>
to makeGlslType
static:Change
UniformInt
to "override"GlslType
, keeping the static modifier:Fill
???
withnull, null
:Solution 3
Use attributes instead. Something like:
Conclusion
All 3 of these solutions are pretty similar and seem to have the same drawbacks (can't enforce derived class to implement it). Throwing an exception via method 1 or 2 will help find errors quickly, or with 3 I can just skip over classes that don't have the attribute by modifying my
fields
condition.