有没有更好的方法来自引用类型?

发布于 2024-08-05 16:37:04 字数 2614 浏览 3 评论 0原文

我最近发现很多与在 C# 中引用泛型类相关的代码味道。我的抱怨尤其适用于那些继承自 DependencyObject 并包含 DependencyProperties 的类。

基本问题是,在声明依赖属性时,通常会引用当前类型,也称为所有者。这工作得很好,一般来说,对于简单的非泛型对象来说,这并不是什么大问题,除非对象包含多个依赖属性,然后类型名称需要在不同的地方进行重构(通过重构可以更容易)视觉工作室)。

public class MyDependencyObject : DependencyObject
{
    public int MyProperty
    {
        get { return (int)GetValue(MyPropertyProperty); }
        set { SetValue(MyPropertyProperty, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.Register("MyProperty", typeof(int), typeof(MyDependencyObject), new UIPropertyMetadata(0));
}

但我最近发现,当将这种繁重的显式自引用实践与泛型的广泛使用结合起来时,代码确实开始变得丑陋。

public class MyDependencyObject<TypeA, TypeB, TypeC, TypeD> : DependencyObject
{
    public int MyProperty1
    {
        get { return (int)GetValue(MyPropertyProperty1); }
        set { SetValue(MyPropertyProperty1, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty1 =
        DependencyProperty.Register("MyProperty1", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));

    public int MyProperty2
    {
        get { return (int)GetValue(MyPropertyProperty2); }
        set { SetValue(MyPropertyProperty2, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty2 =
        DependencyProperty.Register("MyProperty2", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));

    public int MyProperty3
    {
        get { return (int)GetValue(MyPropertyProperty3); }
        set { SetValue(MyPropertyProperty3, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty3 =
        DependencyProperty.Register("MyProperty3", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));

    public int MyProperty4
    {
        get { return (int)GetValue(MyPropertyProperty4); }
        set { SetValue(MyPropertyProperty4, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty4 =
        DependencyProperty.Register("MyProperty4", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));
}

我的问题是,是否有人知道任何技巧、技巧或合法的解决方案,可以减少在上面所示的情况下需要引用带有泛型参数的完整类型名称的次数。

全面披露:我确实在 Microsoft .Connect 网站上提出了这个问题,但他们拒绝了 自引用关键字,但没有提供解决方法或替代解决方案。我的想法是使用一些关键字,例如 OwnerOwnerClassThisType,以便一般地引用关键字所在的类型用过的。

I'm finding lately a lot of code smells related to referencing generic classes in C#. My gripes especially apply to those classes which inherit from DependencyObject and contain DependencyProperties.

The basic problem is that when declaring a dependency property one generally references the current type which is also known as the owner. This works just fine and in general isn't much of a problem for simple non-generic objects except for that when the object contains several dependency properties and then the type name needs to be re-factored in various places (made easier with refactoring in Visual Studio).

public class MyDependencyObject : DependencyObject
{
    public int MyProperty
    {
        get { return (int)GetValue(MyPropertyProperty); }
        set { SetValue(MyPropertyProperty, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.Register("MyProperty", typeof(int), typeof(MyDependencyObject), new UIPropertyMetadata(0));
}

What I've been finding lately though is that when combining this burdonsome explicit self referencing practice with extensive use of generics the code really starts to become ugly.

public class MyDependencyObject<TypeA, TypeB, TypeC, TypeD> : DependencyObject
{
    public int MyProperty1
    {
        get { return (int)GetValue(MyPropertyProperty1); }
        set { SetValue(MyPropertyProperty1, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty1 =
        DependencyProperty.Register("MyProperty1", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));

    public int MyProperty2
    {
        get { return (int)GetValue(MyPropertyProperty2); }
        set { SetValue(MyPropertyProperty2, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty2 =
        DependencyProperty.Register("MyProperty2", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));

    public int MyProperty3
    {
        get { return (int)GetValue(MyPropertyProperty3); }
        set { SetValue(MyPropertyProperty3, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty3 =
        DependencyProperty.Register("MyProperty3", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));

    public int MyProperty4
    {
        get { return (int)GetValue(MyPropertyProperty4); }
        set { SetValue(MyPropertyProperty4, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty4 =
        DependencyProperty.Register("MyProperty4", typeof(int), typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));
}

My question is whether anybody is aware of any tricks, hacks, or legitimate solutions to reducing the number of times the full type name with generic parameters needs to be referenced in situations such as the one shown above.

Full disclosure: I did bring this up as an issue on the Microsoft .Connect site but they rejected the idea of a self referencing keyword but offered no workaround or alternative solution. My idea was to use some keyword such as Owner, OwnerClass, or ThisType in order to generically refer to the type in which the keyword is being used.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

柳絮泡泡 2024-08-12 16:37:04

您可以采取一些措施来减轻疼痛。创建一个包含当前类的类型信息的静态变量。

private static readonly Type ThisType = typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));

public int MyProperty1
{
  get { return (int)GetValue(MyPropertyProperty1); }
  set { SetValue(MyPropertyProperty1, value); }
}

public static readonly DependencyProperty MyPropertyProperty1 = 
    DependencyProperty.Register("MyProperty1", typeof(int), ThisType);

接下来,您可以使用这个巧妙的技巧来制作对 getter 和 setter 的引用重构安全。

private static string GetPropertyName<TSource, TResult>(Expression<Func<TSource, TResult>> expression)
{
  if (expression.NodeType == ExpressionType.Lambda && expression.BodyType == ExpressionType.MemberAccess)
  {
    PropertyInfo pi = (expression.Body as MemberExpression).Member as PropertyInfo;
    if (pi != null)
    {
      return pi.Name;
    }
  }
  throw new ArgumentException("expression", "Not a property expression.");
}

现在你的代码会像这样。

private static readonly Type ThisType = typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));

public int MyProperty1
{
  get { return (int)GetValue(MyPropertyProperty1); }
  set { SetValue(MyPropertyProperty1, value); }
}

public static readonly DependencyProperty MyPropertyProperty1 = 
    DependencyProperty.Register(GetPropertyName((MyDependencyObject x) => x.MyProperty1), typeof(int), ThisType);

There are a couple of things you could do to ease the pain. Create a static variable that contains the type information for the current class.

private static readonly Type ThisType = typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));

public int MyProperty1
{
  get { return (int)GetValue(MyPropertyProperty1); }
  set { SetValue(MyPropertyProperty1, value); }
}

public static readonly DependencyProperty MyPropertyProperty1 = 
    DependencyProperty.Register("MyProperty1", typeof(int), ThisType);

Next you could use this clever trick to make the references to your getter and setters refactor safe.

private static string GetPropertyName<TSource, TResult>(Expression<Func<TSource, TResult>> expression)
{
  if (expression.NodeType == ExpressionType.Lambda && expression.BodyType == ExpressionType.MemberAccess)
  {
    PropertyInfo pi = (expression.Body as MemberExpression).Member as PropertyInfo;
    if (pi != null)
    {
      return pi.Name;
    }
  }
  throw new ArgumentException("expression", "Not a property expression.");
}

Now your code would like this.

private static readonly Type ThisType = typeof(MyDependencyObject<TypeA, TypeB, TypeC, TypeD>));

public int MyProperty1
{
  get { return (int)GetValue(MyPropertyProperty1); }
  set { SetValue(MyPropertyProperty1, value); }
}

public static readonly DependencyProperty MyPropertyProperty1 = 
    DependencyProperty.Register(GetPropertyName((MyDependencyObject x) => x.MyProperty1), typeof(int), ThisType);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文