【问题标题】:Object with user-configurable property "visibility"具有用户可配置属性“可见性”的对象
【发布时间】:2012-06-04 20:55:22
【问题描述】:

我有一个带有一堆属性的用户对象。我有一个要求,即当用户设置他们的信息时,他们需要能够说明其个人资料的哪些属性对其他人可见。

我设想的方式是添加一个附加属性 - 一个字符串列表,其中包含公开可见的属性名称。然后我可以实现一个名为 ToPublicView() 的方法或类似的方法,使用反射将非公共属性设置为 null 或默认值。

这是一个合理的方法,还是有更好的方法?

【问题讨论】:

  • 我认为这是最简单的选项。如果反射开始影响你的表现,你可能需要一个属性委托字典来访问这些值。
  • 什么?这是一个疯狂、疯狂、疯狂的选择。
  • 为什么?要求不具有动态属性,因此以动态方式拥有所有属性是没有意义的。此外,当您必须将它们用于应用程序的其余部分时,将它们作为实际属性将使代码更具可读性。
  • 业务需求与您实际编写的代码没有直接关系。如果是这样,那会有点疯狂,不是吗?
  • 很高兴看到大家都同意 ;) 我喜欢 Property 对象的想法,但我仍然不确定措辞强硬的反对(“疯狂、疯狂、疯狂”)背后的确切原因。我只是想知道原因是什么,因为最初的想法仍然吸引我。

标签: c# oop properties


【解决方案1】:

在这种情况下,如果可能的话,我建议您简单地列出您的属性,例如:

public Class Property<T>
{
    public Property(string name, bool visible, T value)
    {
        Name = name;
        Visible = visible;
        Value = value;
    }

    string Name { get; set; }
    bool Visible { get; set; }
    T Value { get; set; }
}

然后你可以像这样创建一个属性列表:

List<Property> properties = new List<Property>();
properties.Add(new Property<string>("FirstName", true, "Steve"));

如果您今天需要设置可见性,那么明天您可能还需要设置其他元属性。颜色?必需/可选?尺寸?等等。拥有自己的属性类型可以让您在未来轻松扩展它。

【讨论】:

  • 除了我猜你应该对 Visible 属性使用某种枚举,使名称强不可变(将其定义为只读),并为通用方差添加一个接口(相反) .至少。您可以存储一个像 IEnumerable> 这样的枚举,或者定义一个单独的 IProperty 对象,它是 IProperty 的超级对象
  • 超级架构/复杂。
  • 我并没有说这是所有场景中最好的情况。如果没有关于海报确切情况的更多细节,很难确定。但是,在很多情况下,我认为这将是最好的解决方案。但是,我可以很容易地想象(因为我在自己的经验中遇到过)您不想要这样的动态列表,而想要实际属性的情况。这就是为什么我说“如果可能”。我认为这是值得一提的选项,以防它在未来几天确实符合海报或任何其他读者的需求。
【解决方案2】:

什么?不。如果这是需求,那么用户属性应该使用实际属性来实现,而是使用某种 IEnumerable 和 Property 对象,其中每个属性都有其可见性等。

【讨论】:

    【解决方案3】:

    可以使用,可能是自定义DynamicObject 实现的某种组合

    编辑

      //custom property class
      public class MyProperty
      {
          public bool IsVisible { get; set; }
          public string PropertyName { get; set; }
      }
    
      public class Dymo: DynamicObject
      {
    
          Dictionary<MyProperty, object> dictionary
              = new Dictionary<MyProperty, object>();
    
          public override bool TryGetMember(
              GetMemberBinder binder, out object result)
          {
              result = false;
              var prop = PropertyFromName(binder.Name);
              if (prop != null && prop.IsVisible)
                  return dictionary.TryGetValue(prop, out result);
    
              return false;
    
          }
    
          public override bool TrySetMember(
              SetMemberBinder binder, object value)
          {
    
              var prop = PropertyFromName(binder.Name);
              if (prop != null && prop.IsVisible)
                  dictionary[prop] = value;
              else
                  dictionary[new MyProperty { IsVisible = true, PropertyName = binder.Name}] = value;
              return true;
          }
    
          private MyProperty PropertyFromName(string name)
          {
              return (from key in dictionary.Keys where key.PropertyName.Equals(name) select key).SingleOrDefault<MyProperty>();
          }
    
    
          public void SetPropertyVisibility(string propertyName, bool visibility)
          {
              var prop = PropertyFromName(propertyName);
              if (prop != null)
                  prop.IsVisible = visibility;         
          }
      }
    

    并在这样之后使用它。

    dynamic dynObj = new Dymo();
    dynObj.Cartoon= "Mickey" ;
    dynObj.SetPropertyVisibility("Mickey", false); //MAKE A PROPERTY "INVISIBLE"
    

    【讨论】:

    • 哎呀,只是在我要维护的代码中想象这样的事情会伤害我的大脑。
    • @erikkallen:你的大脑不能成为投反对票的理由,抱歉。如果你能找到一些真正的理由,不客气。这是简单明了的解决方案,在这里看不到任何复杂的东西。顺便说一句,这只是一个示例(但仍然有效),可以对其进行优化以适应 OP 的需求。
    • 我不认为这是一个糟糕的解决方案,但我需要一个更强大/更少动态的类型。当然,这对我来说是将来要记住的事情。
    【解决方案4】:

    我认为这是最简单的选项。如果反射开始影响您的性能,您可能需要一个属性委托字典来访问这些值。

    并且由于要求不是具有动态属性而只是标记现有属性,因此以动态方式拥有所有属性(如属性对象列表)是没有意义的。此外,当您必须将它们用于应用程序的其余部分时,将它们作为实际属性将使代码更具可读性。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-06-28
      • 2016-12-23
      • 2015-11-19
      • 2019-11-13
      • 1970-01-01
      • 1970-01-01
      • 2011-02-23
      • 1970-01-01
      相关资源
      最近更新 更多