据我所知C#
不支持虚拟静态属性。如何在C#
中实现这种行为?
我想存档一个基类的所有派生类必须重写静态属性。获取派生类型,我想访问一个名为Identifier
的静态属性
Type t = typeof(DerivedClass);
var identifier= (String) t.GetProperty("Identifier", BindingFlags.Static).GetValue(null, null);
最佳答案
对于考虑相同问题并通过谷歌搜索到达此职位的人,请考虑使用abstract factory pattern而不是此处的解决方案。
--
因为大约五年后您仍然没有正确的答案,所以让我尝试一下。
我曾经考虑过将Curiously Recurring Template Pattern作为一种解决方法,但是由于您将打开BaseClass
进行继承,所以这不是一个好主意。您可能想看看Mr. Lippert's blogpost以便更好地理解其原因。
public abstract class BaseClass {
protected static void Register<U>(String identifier) where U : BaseClass {
m_identities.Add(typeof(U).GetHashCode(), identifier);
}
public static String GetIdentifier<U>() where U : BaseClass {
var t = typeof(U);
var identifier = default(String);
RuntimeHelpers.RunClassConstructor(t.TypeHandle);
m_identities.TryGetValue(t.GetHashCode(), out identifier);
return identifier;
}
static Dictionary<int, String> m_identities = new Dictionary<int, String> { };
}
public class DerivedClassA:BaseClass {
static DerivedClassA() {
BaseClass.Register<DerivedClassA>("12dc2490-065d-449e-a199-6ba051c93622");
}
}
public class DerivedClassB:BaseClass {
static DerivedClassB() {
BaseClass.Register<DerivedClassB>("9745e24a-c38b-417d-a44d-0717e10e3b96");
}
}
测试:
Debug.Print("{0}", BaseClass.GetIdentifier<DerivedClassA>());
Debug.Print("{0}", BaseClass.GetIdentifier<DerivedClassB>());
通过类型初始化器,这是一个相对简单的模式。
Register
方法仅公开给派生类。并且GetIdentifier
和Register
方法都被限制为使用从BaseClass
派生的类型实参调用。尽管我们不强制派生类重写任何内容,但如果它不进行自身注册,GetIdentifier
不会识别它并返回null
。public abstract class BaseClass {
public abstract String Identifier {
get;
}
public static Type GetDerivedClass(String identifier) {
return m_aliases[identifier];
}
public static String GetIdentifier(Type t) {
var value = default(String);
if(t.IsSubclassOf(typeof(BaseClass))) {
var key = t.GetHashCode();
if(!m_identities.TryGetValue(key, out value)) {
value=""+key;
m_aliases.Add(value, t);
m_identities[key]=value;
}
}
return value;
}
static void UpdateAlias(BaseClass x) {
var t = x.GetType();
var value = x.Identifier;
m_aliases.Add(value, t);
m_identities[t.GetHashCode()]=value;
}
protected BaseClass() {
BaseClass.UpdateAlias(this);
}
static Dictionary<String, Type> m_aliases = new Dictionary<String, Type> { };
static Dictionary<int, String> m_identities = new Dictionary<int, String> { };
}
public class DerivedClassA:BaseClass {
public override String Identifier {
get {
return "just text";
}
}
}
public class DerivedClassB:BaseClass {
public override String Identifier {
get {
return "just text";
}
}
}
和测试:
public static void TestMethod() {
var idBeforeInstantiation = BaseClass.GetIdentifier(typeof(DerivedClassA));
var y = new DerivedClassA { };
var idAfterInstantiation = BaseClass.GetIdentifier(typeof(DerivedClassA));
Debug.Print("B's: {0}", BaseClass.GetIdentifier(typeof(DerivedClassB)));
Debug.Print("A's after: {0}", idAfterInstantiation);
Debug.Print("A's before: {0}", idBeforeInstantiation);
Debug.Print("A's present: {0}", BaseClass.GetIdentifier(typeof(DerivedClassA)));
var type1 = BaseClass.GetDerivedClass(idAfterInstantiation);
var type2 = BaseClass.GetDerivedClass(idBeforeInstantiation);
Debug.Print("{0}", type2==type1); // true
Debug.Print("{0}", type2==typeof(DerivedClassA)); // true
Debug.Print("{0}", type1==typeof(DerivedClassA)); // true
var typeB=BaseClass.GetDerivedClass(BaseClass.GetIdentifier(typeof(DerivedClassB)));
var x = new DerivedClassB { }; // confilct
}
显然,这是一个更复杂的解决方案。如您所见,
idBeforeInstantiation
和idAfterInstantiation
是不同的,但是它们都是DerivedClassA
的有效标识符。 m_identities
包含每个派生类的最后更新的标识符,而m_aliases
将包含派生类的所有标识符别名。由于虚拟和静态的组合当前不是该语言的功能(可能永远不会..),因此,如果要强制执行替代,则必须通过一些变通办法来实现。如果选择solution2,则可能希望实现自己的UpdateAlias
,以防止派生类为单个类型提供过多的各种别名,尽管它们都是有效的。故意放置测试中的最后一条语句以演示标识符的冲突。对于这两种解决方案,它们是为不考虑实例化派生类而精心设计的,它们都不要求这样做。