我想强制子类定义一个常量值.
喜欢
const string SomeConstantEverySubclassMustDefine = "abc";
Run Code Online (Sandbox Code Playgroud)
我需要它,因为我需要将它绑定到Type,而不是实例,并且您不能覆盖静态方法/属性iirc.
我真的想对这些常量进行编译时检查.
让我更详细地解释一下:
我们的域模型中的某些类是特殊的,您可以根据类型为它们采取某些操作.因此逻辑与类型有关.要采取的操作需要绑定到类型的字符串.我确实可以每次创建一个实例作为变通方法并声明一个抽象属性,但这不是我想要的.我想在编译时强制执行字符串的声明,只是为了确定.
Jon*_*eet 20
不,你不能.我建议你使用抽象属性使你的基类抽象,你可以在需要时获取它.然后,每个子类只需要返回一个常量即可实现该属性.缺点是你不能在基类中的静态方法中使用它 - 但是那些与子类无关.
(它还允许子类在每个实例中自定义属性,如果需要的话......但这很少是实际问题.)
如果这对您不够,您可能需要考虑并行类型层次结构.基本上,多态性在.NET中不会以特定于类型的方式发生; 仅以特定于实例的方式.
如果您仍然希望这样做并使用反射获取它,我建议您只编写单元测试以确保定义相关常量.当你超越类型系统可以描述的范围时,这通常是你能做的最好的事情.
做一个abstract property只有一个get.这就是我认为你可以做的强制一个类有价值.然后你可以在属性中返回一个常量.
例如:
基类:
public abstract string MyConst { get; }
Run Code Online (Sandbox Code Playgroud)
然后在派生类中
public override string MyConst {
get { return "constant"; }
}
Run Code Online (Sandbox Code Playgroud)
这就是我如何使我的工作.我使用了其他人建议的属性.
public class ObjectAttribute : Attribute
{
public int ObjectSize { get; set; }
public ObjectAttribute(int objectSize)
{
this.ObjectSize = objectSize;
}
}
public abstract class BaseObject
{
public static int GetObjectSize<T>() where T : IPacket
{
ObjectAttribute[] attributes = (ObjectAttribute[])typeof(T).GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
}
[ObjectAttribute(15)]
public class AObject : BaseObject
{
public string Code { get; set; }
public int Height { get; set; }
}
[ObjectAttribute(25)]
public class BObject : BaseObject
{
public string Code { get; set; }
public int Weight { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果您希望实例访问该属性,只需将其添加到基本抽象类.
public abstract class BaseObject
{
public static int GetObjectSize<T>() where T : IPacket
{
ObjectAttribute[] attributes = (ObjectAttribute[])typeof(T).GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
public int ObjectSize
{
get
{
ObjectAttribute[] attributes = (ObjectAttribute[])GetType().GetCustomAttributes(typeof(ObjectAttribute), false);
return attributes.Length > 0 ? attributes[0].ObjectSize : 0;
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用常量
int constantValueA = AObject.GetObjectSize<AObject>();
int constantValueB = BObject.GetObjectSize<BObject>();
AObject aInstance = new AObject();
int instanceValueA = aInstance.ObjectSize;
Run Code Online (Sandbox Code Playgroud)
这是一个奇怪的想法:不是直接使用继承,而是创建一个单独的类,为从某种类型派生的每个类型提供常量值T.此类型的构造函数使用反射来验证是否确实为每个派生类型提供了值.
public abstract class Constant<T, TConstant>
{
private Dictionary<Type, TConstant> _constants;
protected Constant()
{
_constants = new Dictionary<Type, TConstant>();
// Here any class deriving from Constant<T, TConstant>
// should put a value in the dictionary for every type
// deriving from T, using the DefineConstant method below.
DefineConstants();
EnsureConstantsDefinedForAllTypes();
}
protected abstract void DefineConstants();
protected void DefineConstant<U>(TConstant constant) where U : T
{
_constants[typeof(U)] = constant;
}
private void EnsureConstantsDefinedForAllTypes()
{
Type baseType = typeof(T);
// Here we discover all types deriving from T
// and verify that each has a key present in the
// dictionary.
var appDomain = AppDomain.CurrentDomain;
var assemblies = appDomain.GetAssemblies();
var types = assemblies
.SelectMany(a => a.GetTypes())
.Where(t => baseType.IsAssignableFrom(t));
foreach (Type t in types)
{
if (!_constants.ContainsKey(t))
{
throw new Exception(
string.Format("No constant defined for type '{0}'.", t)
);
}
}
}
public TConstant GetValue<U>() where U : T
{
return _constants[typeof(U)];
}
}
Run Code Online (Sandbox Code Playgroud)
基本示例:
public class BaseType
{
public static Constant<BaseType, string> Description { get; private set; }
static BaseType()
{
Description = new BaseTypeDescription();
}
}
public class DerivedType : BaseType
{ }
internal sealed class BaseTypeDescription : Constant<BaseType, string>
{
public BaseTypeDescription() : base()
{ }
protected override DefineConstants()
{
DefineConstant<BaseType>("A base type");
DefineConstant<DerivedType>("A derived type");
}
}
Run Code Online (Sandbox Code Playgroud)
现在我有了允许我这样做的代码:
var description = BaseType.Description;
// returns "A base type"
string baseTypeDescription = description.GetValue<BaseType>();
// returns "A derived type"
string derivedTypeDescription = description.GetValue<DerivedType>();
Run Code Online (Sandbox Code Playgroud)
您可能不喜欢它,但最接近的方法是声明一个抽象的只读(无set)属性.
如果你有一个子类的实例,那么这可以和常量一样工作,即使它在技术上是实例级的(它对于给定类的所有实例都是一样的).
例如,考虑一下IList.IsReadOnly.在大多数情况下,这实际上是一个告诉您底层类实现的属性,而不是特定于特定实例的任何状态.(它可能是一个接口成员而不是抽象类成员,但它的想法是一样的.)
如果你试图静态访问它,那么......那你运气不好.但在这种情况下,我无法看到你如何在不使用反射的情况下获得价值.也许那是你的意图; 我不知道.