2

.net FrameWork 3.5では、以下のコードを使用してプロパティ情報を取得できます。

using System;
using System.Linq.Expressions;
using System.Reflection;

class Foo
{
    public string Bar { get; set; }
}
static class Program
{
    static void Main()
    {
        PropertyInfo prop = PropertyHelper<Foo>.GetProperty(x => x.Bar);
    }
}
public static class PropertyHelper<T>
{
    public static PropertyInfo GetProperty<TValue>(
        Expression<Func<T, TValue>> selector)
    {
        Expression body = selector;
        if (body is LambdaExpression)
        {
            body = ((LambdaExpression)body).Body;
        }
        switch (body.NodeType)
        {
            case ExpressionType.MemberAccess:
                return (PropertyInfo)((MemberExpression)body).Member;
            default:
                throw new InvalidOperationException();
        }
    }
}

これは、クラスのインスタンスを作成してプロパティメンバーにアクセスすることによっても実行できます。では、プロパティ情報の利点は何ですか?

4

2 に答える 2

4

PropertyInfoクラスのプロパティの情報を取得するために使用されます。インスタンスを作成する必要はありません。利点は、タイプミスの可能性を排除することです。

Expressionsはまったく異なる概念です (Reflection を内部で使用します)。式は、メソッド本体をツリー構造として表現するために使用されます。これにより、実行時にメソッド定義を柔軟に作成/調整できます。

Expressions のこの機能は、Queryableクラスによって利用され、リモート ソースで動的クエリを構築/実行します。

例、INotifyPropertyChangedインターフェースを考えてみましょう。プロパティの変更通知に使用されます。

通常の実装では、プロパティ名を文字列パラメーターとして受け取ります。したがって、入力エラーは実行時に検出されます。また、リファクタリングによってコードが壊れる可能性があります (ただし、スマート リファクタリング ツールはこれを処理します)。

    void RaisePropertyChanged(PropertyChangedEventArgs args)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public string Name
    {
        set
        {
            _name = value;
            RaisePropertyChanged("Name"); // Property name is specified as string
        }
    }

より良い実装 (ただしパフォーマンス効率は良くありません) は、プロパティ名を としExpressionます。

    void RaisePropertyChanged<T>(Expression<Func<T>> selectorExpression)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            MemberExpression body = selectorExpression.Body as MemberExpression;

            handler(this, new PropertyChangedEventArgs(body.Member.Name));
        }
    }

    public string Name
    {
        set
        {
            _name = value;
            RaisePropertyChanged( () => this.Name); // Property is specified instead of name that removes typing error
        }
    }
于 2013-01-03T03:46:59.703 に答える
0

式を分析して PropertyInfo を取得する利点は、コンパイル時のチェックが可能になり、リファクタリングのサポートが向上することです。

たとえば、プロパティの名前を Bar から Barr に変更すると、コードがコンパイルされなくなるため、アプリケーションを実際に実行しなくても、無効なメンバー アクセスのバグを見つけることができます。

どのプロパティにアクセスする必要があるかが事前にわかっている場合は、式を使用することをお勧めします。

たとえば、グリッド列やリスト コントロールにバインドするプロパティの名前を指定する必要があるデータ バインド シナリオでは、式が特に役立つことがわかりました。このタイプのシナリオで式を使用すると、メンテナンス コストが大幅に削減されます。

式を使用して、独自の PropertyHelper クラスでグリッド列の書式設定を実行する例を次に示します。

GridForm.FormatGrid() にジャンプして、重要なビットを表示します。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq.Expressions;
using System.Reflection;
using System.Windows.Forms;

namespace ExpressionSample
{
    public class TestEntity
    {
        public int ID { get; set; }
        public string Text { get; set; }
        public decimal Money { get; set; }
    }

    public partial class GridForm : Form
    {
        public GridForm()
        {
            this.InitializeComponent();
        }

        private void GridForm_Load(object sender, EventArgs e)
        {
            this.FillGrid();
            this.FormatGrid();
        }

        private void FillGrid()
        {
            this.DataGridView.DataSource = TestDataProducer.GetTestData();
        }

        private void FormatGrid()
        {
            var redCellStyle = new DataGridViewCellStyle() { ForeColor = Color.Red };
            var moneyCellStyle = new DataGridViewCellStyle() { Format = "$###,###,##0.00" };

            this.GridColumn(e => e.ID).Visible = false;
            this.GridColumn(e => e.Text).DefaultCellStyle = redCellStyle;
            this.GridColumn(e => e.Money).DefaultCellStyle = moneyCellStyle;
        }

        private DataGridViewColumn GridColumn<TProperty>(Expression<Func<TestEntity, TProperty>> expr)
        {
            var propInfo = PropertyHelper<TestEntity>.GetProperty(expr);
            var column = this.DataGridView.Columns[propInfo.Name];

            return column;
        }
    }

    public static class PropertyHelper<T>
    {
        public static PropertyInfo GetProperty<TValue>(
            Expression<Func<T, TValue>> selector)
        {
            Expression body = selector;
            if (body is LambdaExpression)
            {
                body = ((LambdaExpression)body).Body;
            }
            switch (body.NodeType)
            {
                case ExpressionType.MemberAccess:
                    return (PropertyInfo)((MemberExpression)body).Member;
                default:
                    throw new InvalidOperationException();
            }
        }
    }

    public static class TestDataProducer
    {
        public static IList<TestEntity> GetTestData()
        {
            var entities = new List<TestEntity>();

            for (var i = 1; i <= 10; i++)
            {
                var testEntity = new TestEntity {
                    ID = i,
                    Text = "Entity " + i.ToString(),
                    Money = i * 100m
                };

                entities.Add(testEntity);
            }

            return entities;
        }
    }
}
于 2013-01-03T04:00:48.607 に答える