具有用户可配置属性“visibility”的对象

5
我有一个User对象,它有很多属性。我的要求是当用户设置他们的信息时,他们需要能够指定他们资料中哪些属性对其他人可见。
我设想的方法是添加一个额外的属性——一个字符串列表,其中包含公开可见的属性名称。然后,我可以实现一个名为ToPublicView()或类似的方法,使用反射将非公共属性设置为null或默认值。
这种方法合理吗?还是有更好的办法?

我认为这是最简单的选项。如果反射开始影响性能,您可能需要拥有一个属性委托字典来访问值。 - Ivo
什么?这是一个疯狂的、疯狂的、疯狂的选项。 - GregRos
为什么?要求不具备动态属性,因此以动态方式拥有所有属性是没有意义的。此外,将它们作为实际属性使得在应用程序的其余部分中使用代码更加易读。 - Ivo
“业务需求”与您实际编写的代码并没有直接关系。如果有关系的话,那就有点疯狂了,不是吗? - GregRos
很高兴看到大家都同意 ;) 我喜欢属性对象的想法,但我仍然不确定强烈反对(“疯狂,疯狂,疯狂”)背后的确切原因。我只是想知道原因,因为原始想法仍然吸引我。 - Cork
我决定坚持我的原始想法。这个类保持简单,性能也不是问题。我不确定为什么它被如此严厉地批评。在我的笔记本电脑上,使用反射创建一个新用户、设置属性、创建另一个新用户并复制选定的属性,每秒可以发生80000次,而我不希望每个租户每天发生超过几次。@ivowiblo如果您将您的回复发布为答案,我会将其标记为已接受。 - Cork
4个回答

1

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

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


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 属性,将名称定义为强不可变的(定义为只读),并添加一个用于泛型方差(contra- con- whatever)的接口。至少如此。你可以存储一个可枚举对象,例如 IEnumerable<IProperty<object>>,或者定义一个超级 IProperty 对象,它是 IProperty<T> 的父类。 - GregRos
过于超级架构化/复杂化。 - Ivo
我并没有说这是在所有情况下最佳的解决方案。如果没有更多关于发帖者具体情况的细节,很难确定。但是,在许多情况下,我认为这将是最好的解决方案。然而,我可以轻松想象(因为我在自己的经验中遇到过)一些情况,你不想要像这样的动态列表,而是想要实际属性。这就是为什么我说“如果可能”的原因。我认为值得提及这个选项,以防它符合发帖者或未来任何其他读者的需求。 - Steven Doggart

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

0

可以使用一些自定义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
@erikkallen:你的大脑不应该成为拒绝投票的理由,抱歉。如果你能找到一些真正的理由,那么欢迎您提出。这是一个简单明了的解决方案,我没有看到任何复杂的东西。顺便说一下,这只是一个示例(但可以工作),可以进行优化以适应OP的需求。 - Tigran
我不认为这是一个糟糕的解决方案,但我需要更强/不那么动态的类型。对于我来说,这是未来需要记住的事情。 - Cork

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接