如何实现虚拟静态属性? [英] How to implement virtual static properties?
问题描述
据我所知 C#
不支持虚拟静态属性。如何在 C#
中实现这种行为?
As far as I know C#
doesn't support virtual static properties. How to implement such a behavior in C#
?
我想存档一个基类的所有派生类都必须覆盖静态属性。获取派生类型时,我想访问名为 Identifier
I want to archive that all derived classes of a base class must override a static property. Getting a derived type, I want to access to a static property called Identifier
Type t = typeof(DerivedClass);
var identifier= (String) t.GetProperty("Identifier", BindingFlags.Static).GetValue(null, null);
推荐答案
对于那些想到同一件事并达到目标的人通过谷歌搜索发布,请考虑抽象工厂模式,而不是此处的解决方案。
For people who think about the same thing and reach this post by googling, consider abstract factory pattern rather than the solutions here.
-
因为五年后您仍然没有正确的答案,让我给
For you still don't have an accpted answer about five years later, let me give it a try(again) ..
我曾经想过好奇地重复使用模板模式作为一种解决方法,但是由于您将打开 BaseClass
进行继承,所以这不是一个好主意。您可能想看看先生。利珀特(Lippert)的博客文章,以更好地理解其原因。
I've ever thought about the Curiously Recurring Template Pattern as a workaround, but since you'll open BaseClass
for inheritance it would not be a good idea. You might want to have a look at Mr. Lippert's blogpost for a better understanding of why.
-
解决方案1 :您不注册,我不认识..
Solution 1: You don't register, I don't recognize ..
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");
}
}
测试:
test:
Debug.Print("{0}", BaseClass.GetIdentifier<DerivedClassA>());
Debug.Print("{0}", BaseClass.GetIdentifier<DerivedClassB>());
这是通过类型初始化器。 Register
方法仅公开给派生类。并且 GetIdentifier
和 Register
方法都被限制为使用从<$ c $派生的类型参数调用c> BaseClass 。尽管我们不强制派生类重写任何内容,但如果未注册自身,则 GetIdentifier
不能识别它并返回 null
。
This is is a relatively simple pattern through the type initializer. The Register
method is only exposed to derived class; and both the GetIdentifier
and Register
methods are constrained to be invoked with a type argument which is derived from BaseClass
. Although we don't force the derived classes to override anything, if it doesn't register itself, GetIdentifier
doesn't recognize it and returns null
.
-
解决方案2 :在您显示身份之前,我为您提供了默认设置。只要您没有歧义,我相信您以为自己是谁。
Solution 2: Before you show your identity, I buy you a default. Whoever you think you are, I believe -- as long as there are no ambiguity.
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";
}
}
}
和测试:
and the test:
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
包含派生类的所有标识符别名。由于 virtual 和 static 的组合当前不是该语言的功能(可能永远不会..),如果我们要强制执行 override ,则我们必须通过一些解决方法来做到这一点。如果您选择solution2,则您可能想实现自己的 UpdateAlias
,以防止派生类为单个类型提供过多的各种别名,尽管它们都是有效。故意放置测试中的最后一条语句以演示标识符的冲突。
Apparently this is a more complicated solution. As you can see idBeforeInstantiation
and idAfterInstantiation
are different, however, they are either valid identifiers for DerivedClassA
. m_identities
contains the last updated identifier for each derived class and m_aliases
will contain all the identifier aliases for the derived classes. Since the combination of virtual and static is not a feature of the language currently(maybe never ..), if we want enforce the override then we have to do it through some workaround. If you'll choose solution2, You might want to implemenet you own UpdateAlias
to prevent the derived classes from providing too much of various aliases for a single type, though they will all be valid. The last statement in the test are put deliberately to demonstrate the conflict of identifiers.
这两种解决方案都是为您考虑不要实例化派生类而精心设计的,它们都不是不需要 >那个。
For these two solutions are carefully designed for your consideration of not to instantiate the derived classes, none of them requires that.
这篇关于如何实现虚拟静态属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!