3

いくつかの文字列値を保持する Customer と呼ばれるいくつかのセッターとゲッターを持つクラスがあります。次に、List を作成し、Customer クラスの多くをそれに追加します。リフレクションを使用して getter メソッドと setter メソッドにアクセスするにはどうすればよいですか?

List<Customer> Customers; // assume we have filled it
Customers[0].Name; // how do I use reflection to call this from a string?

また、Customer クラス、Customers、および Name メソッドはすべてパブリックです。

ユーザーが編集しようとしている列に基づいて、クラスから動的に値を取得する必要がある状況にあります。列名は、呼び出す必要があるメソッドの名前です。

GetType().GetMethod() を調べましたが、私の質問は、上記のようなリストでそれを使用する方法です。

例は私の問題を解決します。

4

4 に答える 4

2

更新: リファクタリング セーフ コードを使用してメソッドまたはプロパティにアクセスする方法を説明し、コードを提供する素敵な投稿があります。 http://www.codeducky.org/10-utilities-c-developers-should-know-part-two/


与えられたすべての答えが機能します。ただし、どれもリファクタリング セーフではありません。もう少し安全にリファクタリングできるソリューションを提供したいと思いました。

//Create a dictionary of columnName => property info using the GetPropertyInfo method.
public static IDictionary<string, PropertyInfo> propertyInfos = new Dictionary<string, PropertyInfo>
    {
        {"Name", GetPropertyInfo((Customer c) => c.Name) }
    };

List<Customer> Customers= new List<Customer> { new Customer { Name = "Peter Pan" } };
Customer customer = Customers[0];
string column = "Name";
PropertyInfo propertyInfo = propertyInfos[column];
//Set property
propertyInfo.SetValue(customer, "Captain Hook", null);
//Get property -- Returns Captain Hook
object propertyValue = propertyInfo.GetValue(customer, null);

私はこの答えGetPropertyInfoから取ってきました。HappyNomadさんのコメントで最新バージョンのC#では必要ないことがわかるので、パラメータを削除して少し修正しました。source

public static PropertyInfo GetPropertyInfo<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertyLambda)
{
    Type type = typeof(TSource);

    MemberExpression member = propertyLambda.Body as MemberExpression;
    if (member == null)
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a method, not a property.",
            propertyLambda.ToString()));

    PropertyInfo propInfo = member.Member as PropertyInfo;
    if (propInfo == null)
        throw new ArgumentException(string.Format(
            "Expression '{0}' refers to a field, not a property.",
            propertyLambda.ToString()));

    if (type != propInfo.ReflectedType &&
        !type.IsSubclassOf(propInfo.ReflectedType))
        throw new ArgumentException(string.Format(
            "Expresion '{0}' refers to a property that is not from type {1}.",
            propertyLambda.ToString(),
            type));

    return propInfo;
}

Nameのプロパティを変更するたびにコンパイル時エラーが発生するため、私の提案はもう少しリファクタリングに安全ですCustomer

補足:ティム S.に同意します。リフレクションよりも安全でパフォーマンスの高い方法を見つけることができるでしょう:)。

于 2013-06-01T14:41:42.463 に答える
1

これがあなたが求めていることに対する答えです:

void Main()
{
    List<Customer> Customers= new List<Customer> { new Customer { Name = "John Smith" } };
    GetProp(Customers[0], "Name"); // "John Smith"
    SetProp(Customers[0], "Name", "Joe");
    GetProp(Customers[0], "Name"); // "Joe"
}
object GetProp(Customer customer, string propertyName)
{
    var property = typeof(Customer).GetProperty(propertyName);
    return property.GetValue(customer);
}
void SetProp(Customer customer, string propertyName, object propertyValue)
{
    var property = typeof(Customer).GetProperty(propertyName);
    property.SetValue(customer, propertyValue);
}

または、厳密に型指定されていないリストに取り組んでいます:

void Main()
{
    List<Customer> Customers= new List<Customer> { new Customer { Name = "John Smith" } };
    string name = (string)GetProp(Customers, 0, "Name"); // name == "John Smith"
}
object GetProp(object customerList, int index, string propertyName)
{
    var custList = (IList)customerList;
    var customer = custList[index];
    var nameProperty = customer.GetType().GetProperty(propertyName);
    return nameProperty.GetValue(customer);
}

テーブル/グリッドの値を変更する際にリフレクションを使用しないでください。また、列名に基づいて使用しないでください (表示値とプロパティ名は常に同じであるとは限りません)。あなたは何をするべきか?それは、使用しているフレームワークによって異なります: WPF? ASP.NET Web サイト? ウィンフォーム?

于 2013-06-01T14:00:02.920 に答える
1

質問の「動的」部分がどこから始まるかによって異なります。リスト自体に動的にアクセスする必要がありますか? その場合、2 つの動的 (リフレクション) 呼び出しを行う必要があります。ただし、リストに直接アクセスでき、インデクサーを使用して適切な顧客を見つけることができ、その場合にのみリフレクションコールを使用する必要がある場合、コードは次のようになります。

var fieldName = "Name";
var customer = Customers[x];
Type type = typeof(Customer);
var prop = type.GetProperties().Single(field => field.Name == fieldName);

// once you have your propinfo + your reference to the right customer, just call...
Object value = prop.GetValue(customer, null); // you'll need to cast/convert away from object

詳細については、「 LINQで PropertyInfo オブジェクトを使用してコレクションをクエリする」を参照してください。

于 2013-06-01T13:25:57.077 に答える
1

この例はあなたを始めるはずです:

var namePropertyInfo = typeof(Customer).GetProperty("Name");
var name = namePropertyInfo.GetValue(Customers[0], null);

現在、は に等しい値を持つnameのインスタンスです。それに応じて進みます。objectCustomer[0].Name

于 2013-06-01T13:40:02.300 に答える