【问题标题】:How to implement virtual static properties?如何实现虚拟静态属性?
【发布时间】:2013-02-27 02:30:26
【问题描述】:

据我所知C# 不支持虚拟静态属性。如何在C#中实现这样的行为?

我想归档基类的所有派生类都必须覆盖静态属性。获取派生类型,我想访问一个名为Identifier的静态属性

Type t = typeof(DerivedClass);
var identifier= (String) t.GetProperty("Identifier", BindingFlags.Static).GetValue(null, null);

【问题讨论】:

  • 静态成员不能被覆盖(或者它是“覆盖”?)原谅我的英语不好=(
  • 如你所说,C#不支持,所以你无法实现。
  • 如果真的是static,为什么要virtual
  • 不,我没有对象,只有类型。如果不需要静态对象。

标签: c# properties static virtual


【解决方案1】:

对于有相同想法并通过谷歌搜索到达此帖子的人,请考虑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 方法只对派生类公开;并且GetIdentifierRegister 方法都被限制为使用派生自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
    }
    

显然这是一个更复杂的解决方案。如您所见,idBeforeInstantiationidAfterInstantiation 是不同的,但是它们都是DerivedClassA 的有效标识符。 m_identities 包含每个派生类的最后更新标识符,m_aliases 将包含派生类的所有标识符别名。由于 virtualstatic 的组合目前不是该语言的特征(可能永远不会..),如果我们想强制执行 override 那么我们必须通过一些解决方法来做到这一点。如果您选择解决方案 2,您可能希望实现您拥有的 UpdateAlias 以防止派生类为单一类型提供过多的各种别名,尽管它们都是有效的。测试中的最后一条语句是故意放置的,以证明标识符的冲突。

因为这两个解决方案是为您考虑不实例化派生类而精心设计的,它们都需要

【讨论】:

    【解决方案2】:

    简单地说,你不能,所以我谦虚地建议你离开它并尝试其他东西。

    请在this SO 帖子中查看答案。如果您可以实现这样的功能,您将在继承方面遇到严重问题。

    去过那里,做到了。在我再次清醒后,我采用了常规继承方法。我想你可能也应该这样做。

    【讨论】:

      【解决方案3】:

      另一种不需要注册类但确实需要一些额外工作的方法是创建一个静态类,该类保存每个派生类类型的“静态”数据并返回一个常量/静态值从静态类。让我解释一下这种方法的细节。

      对于类的每个成员都具有始终相同的静态属性的一个重要原因是避免不必要的内存使用和重复。虽然这里演示的方法并没有完全避免这种情况,但它仍然绕过了大部分“额外”开销。以下示例不满足的唯一用例是,如果使用静态属性的原因是您不必拥有实例,因为您必须拥有实例才能获取数据。

      如果您需要一个对于类的每个成员(静态)始终相同的虚拟字段或属性,请使用返回“常量”或静态数据的非静态属性,如下所示:

      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 } }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-10-31
        • 1970-01-01
        • 1970-01-01
        • 2013-09-02
        • 2011-06-08
        • 1970-01-01
        • 2013-01-24
        相关资源
        最近更新 更多