据我所知C#
不支持虚拟静态属性。如何在C#
?
我想归档基类的所有派生类都必须覆盖静态属性。获取派生类型,我想访问名为Identifier
Type t = typeof(DerivedClass);
var identifier= (String) t.GetProperty("Identifier", BindingFlags.Static).GetValue(null, null);
答案 0 :(得分:4)
简单地说,你不能,所以我谦卑地建议你离开它并尝试别的东西。
请在this SO帖子中查看答案。如果您可以实施此类功能,那么继承会出现严重问题。
去过那里,做到了。在我再次感觉到之后,我采取了常规的继承方法。我想你应该也这样做。
答案 1 :(得分:3)
因为大约五年之后你还没有得到一个认可的答案,让我试一试(再次)..
我曾经考虑过将Curiously Recurring Template Pattern作为一种解决方法,但由于你打开BaseClass
进行继承,这不是一个好主意。您可能希望查看Mr. Lippert's blogpost以更好地了解原因。
解决方案1 :您没有注册,我不认识..
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
。
解决方案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<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
将包含派生类的所有标识符别名。由于虚拟和静态的组合不是当前语言的功能(可能永远不会......),如果我们想要强制执行覆盖那么我们必须通过一些解决方法来做到这一点。如果您选择解决方案2,您可能希望实现自己的UpdateAlias
以防止派生类为单个类型提供过多的别名,尽管它们都是有效的。测试中的最后一个陈述是故意用来证明标识符的冲突。
对于这两个解决方案都是经过精心设计的,以便您考虑不实例化派生类,它们中没有一个需要。
答案 2 :(得分:0)
另一种不需要注册类但需要一些额外工作的方法是创建一个静态类,它保存每个派生类类型的“静态”数据并返回一个常量/静态值来自静态类。让我解释一下这种方法的具体细节。
对于类的每个成员,使静态属性始终相同的一个重要原因是避免不必要的内存使用和重复。虽然这里演示的方法并没有完全避免这种情况,但它仍然绕过了大部分“额外”开销。下面的示例不能满足的唯一用例是,如果使用静态属性的原因是您不必拥有实例,因为您必须有一个实例来获取数据。
如果您需要对类的每个成员(静态)始终相同的虚拟字段或属性,请使用返回“常量”或静态数据的非静态属性,如下所示:
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 } }
}