如何实现虚拟静态属性?
据我所知, C#
不支持虚拟静态属性。 如何在C#
实现这样的行为?
我想归档基类的所有派生类必须覆盖静态属性。 获取派生类型,我想访问名为Identifier
的静态属性
Type t = typeof(DerivedClass); var identifier= (String) t.GetProperty("Identifier", BindingFlags.Static).GetValue(null, null);
因为大约五年后你仍然没有得到一个可接受的答案,让我试试(再次)..
我曾经想过将奇怪的重复模板模式作为一种解决方法,但是因为你将打开BaseClass
inheritance,所以这不是一个好主意。 您可能想看看Lippert先生的博客文章,以便更好地了解原因。
-
解决方案1 :你没有注册,我不承认..
public abstract class BaseClass { protected static void Register(String identifier) where U : BaseClass { m_identities.Add(typeof(U).GetHashCode(), identifier); } public static String GetIdentifier() 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
m_identities = new Dictionary { }; } public class DerivedClassA:BaseClass { static DerivedClassA() { BaseClass.Register ("12dc2490-065d-449e-a199-6ba051c93622"); } } public class DerivedClassB:BaseClass { static DerivedClassB() { BaseClass.Register ("9745e24a-c38b-417d-a44d-0717e10e3b96"); } }
测试:
Debug.Print("{0}", BaseClass.GetIdentifier
()); Debug.Print("{0}", BaseClass.GetIdentifier ());
这是通过类型初始值设定项的相对简单的模式。 Register
方法仅暴露给派生类; 并且GetIdentifier
和Register
方法都被约束为使用从BaseClass
派生的类型参数调用。 虽然我们不强制派生类重写任何东西,但如果它没有自己注册,则GetIdentifier
不会识别它并返回null
。
-
解决方案2 :在您出示身份之前,我会向您购买默认设置。 我相信,无论你认为自己是谁,只要没有歧义。
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
m_aliases = new Dictionary { }; static Dictionary m_identities = new Dictionary { }; }
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
以防止派生类为单个类型提供过多的别名,尽管它们都是有效的。 测试中的最后一个陈述是故意用来certificate标识符的冲突。
对于这两个解决方案是经过精心设计的,以考虑不实例化派生类,它们都不需要 。
简单地说,你不能,所以我谦卑地建议你离开它并尝试别的东西。
请参阅此SOpost中的答案。 如果您可以实现这样的function,那么inheritance会出现严重问题。
去过也做过。 在我再次感觉到之后,我采取了常规的inheritance方法。 我想你应该这样做。
另一种不需要注册类但需要一些额外工作的方法是创建一个静态类,它保存每个派生类类型的“静态”数据,并从静态返回一个常量/静态值类。 让我解释一下这种方法的细节。
对于类的每个成员具有始终相同的静态属性的一个重要原因是避免不必要的内存使用和重复。 虽然这里演示的方法并没有完全避免这种情况,但它仍然绕过了大部分“额外”开销。 下面的示例不能满足的唯一用例是,如果使用静态属性的原因是您不必拥有实例,因为您必须有一个实例来获取数据。
如果您需要对类的每个成员(静态)始终相同的虚拟字段或属性,请使用返回“常量”或静态数据的非静态属性,如下所示:
public static class MyStaticData { public static const string Class1String = "MyString1"; public static const int Class1Int = 1; public static const string Class2String = "MyString2"; public static const int Class2Int = 2; // etc... } public abstract class MyBaseClass { public abstract string MyPseudoVirtualStringProperty { get; } public abstract int MyPseudoVirtualIntProperty { get; } } public class MyDerivedClass1 : My BaseClass { public override string MyPseudoVirtualStringProperty { get { return MyStaticData.Class1String; } } public override int MyPseudoVirtualIntProperty { get { return MyStaticData.Class1Int } } } public class MyDerivedClass2 : My BaseClass { public override string MyPseudoVirtualStringProperty { get { return MyStaticData.Class2String; } } public override int MyPseudoVirtualIntProperty { get { return MyStaticData.Class2Int } } }