23

これがどこかでカバーされている場合は、お詫び申し上げます。投稿する前に調査しました!

さて、質問...私はGetType().GetPropertiesを使用していますが、get / setがない単純なインスタンスフィールドを返していません...そこで、それらを見つける.GetFieldsを使用しました。しかし、フィールドとプロパティを切り替えることなく、値を取得/設定するための単純な単一のオブジェクトを取得したいのですが...これは可能ですか?

私の現在のコードはPropertyInfoで動作しますが、これはうまく機能していますが、それは私が推測するフィールドではありませんか?

[編集] これは私が思いついた解決策であり、うまく機能しています。みんな、ありがとう....

    // some logic borrowed from James Newton-King, http://www.newtonsoft.com
    public static void SetValue(this MemberInfo member, object property, object value)
    {
        if (member.MemberType == MemberTypes.Property)
            ((PropertyInfo)member).SetValue(property, value, null);
        else if (member.MemberType == MemberTypes.Field)
            ((FieldInfo)member).SetValue(property, value);
        else
            throw new Exception("Property must be of type FieldInfo or PropertyInfo");
    }

    public static object GetValue(this MemberInfo member, object property)
    {
        if (member.MemberType == MemberTypes.Property)
            return ((PropertyInfo)member).GetValue(property, null);
        else if (member.MemberType == MemberTypes.Field)
            return ((FieldInfo)member).GetValue(property);
        else
            throw new Exception("Property must be of type FieldInfo or PropertyInfo");
    }

    public static Type GetType(this MemberInfo member)
    {
        switch (member.MemberType)
        {
            case MemberTypes.Field:
                return ((FieldInfo)member).FieldType;
            case MemberTypes.Property:
                return ((PropertyInfo)member).PropertyType;
            case MemberTypes.Event:
                return ((EventInfo)member).EventHandlerType;
            default:
                throw new ArgumentException("MemberInfo must be if type FieldInfo, PropertyInfo or EventInfo", "member");
        }
    }
4

5 に答える 5

34

どうですか:

const BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance;
MemberInfo[] members = type.GetFields(bindingFlags).Cast<MemberInfo>()
    .Concat(type.GetProperties(bindingFlags)).ToArray();

あるいは、FastMemberのようなライブラリは、メンバータイプに関係なく、get / setが同一で、フィールドまたはプロパティのいずれかで問題なく動作します。

于 2012-10-01T20:20:03.453 に答える
11

お気づきのように、GetProperties()とGetFields()の戻りタイプは異なります。GetValue()およびSetValue()を使用してインターフェースを定義し、extendParameterInfoおよびFieldInfoを使用してこのインターフェースを実装する必要があります。これはおそらくラッパーとして機能します。

interface IGetSettable
{
    public void SetValue(
        Object obj,
        Object value,
        Object[] index);
    public Object GetValue(
        Object obj,
        Object[] index);
}

public class ParameterInfoGS : IGetSettable
{
    protected ParameterInfo pi;

    public ParameterInfoExtra(ParameterInfo _pi)
    {
        pi = _pi;
    }

    public void SetValue(
        Object obj,
        Object value,
        Object[] index) {pi.SetValue(obj, value, index);}
    public Object GetValue(
        Object obj,
        Object[] index) {return pi.GetValue(obj, index);}
}

public class FieldInfoGS : IGetSettable
{
    protected FieldInfo pi;

    public FieldInfoExtra(FieldInfo _pi)
    {
        pi = _pi;
    }

    public void SetValue(
        Object obj,
        Object value,
        Object[] index) {pi.SetValue(obj, value, index);}
    public Object GetValue(
        Object obj,
        Object[] index) {return pi.GetValue(obj, index);}
}

public static class AssemblyExtension
{
    public static IGetSettable[] GetParametersAndFields(this Type t)
    {
        List<IGetSettable> retList = new List<IGetSettable>();

        foreach(ParameterInfo pi in t.GetParameters())
            retList.Add(new ParameterInfoExtra(pi));

        foreach(FieldInfo fi in t.GetFields())
            retList.Add(new FieldInfoExtra(fi));

        return retList.ToArray();
    }
}

これにより、次のことが可能になりますGetType().GetParametersAndFields()(つまり、標準の反射タイプを使用します)。

于 2012-10-01T20:15:50.387 に答える
7

少し遅れましたが、私は次のことを思いつきました... 1ループ、チャームのように機能します;-)

        MemberInfo[] memberInfos = dotNetType.GetMembers();
        ModelPropertySpec modelPropertySpec;
        foreach (MemberInfo memberInfo in memberInfos)
        {
            Type itemType = null;
            String memberName = memberInfo.Name;
            switch (memberInfo.MemberType)
            {
                case MemberTypes.Property:
                    itemType = dotNetType.GetProperty(memberName).PropertyType;
                    break;
                case MemberTypes.Field:
                    itemType = dotNetType.GetField(memberName).FieldType;
                    break;
            }

            if (itemType != null)
            {
                modelPropertySpec = ParsePropertyType(memberName, itemType);
                modelSpec.Properties.Add(modelPropertySpec.Name, modelPropertySpec);
            }
        }
于 2013-12-11T09:26:15.673 に答える
5

プロパティまたはフィールドのいずれかを取得するには、次のように言うことができます。

var q=
    from it in type.GetMembers(bindingAttr)
    where it is PropertyInfo||it is FieldInfo
    select it;

どこにあるのbindingAttr

var bindingAttr=
        BindingFlags.NonPublic|
        BindingFlags.Public|
        BindingFlags.Instance;

BindingFlags.NonPublic非公開メンバーを取得したくない場合は削除してください。ちなみに、クエリは単一の呼び出しではなく、単一のステートメントです。


自分でキャストせずにプロパティまたはフィールドの値を取得するにはInvokeMember、次のトリックを使用します。

static object GetValue<T>(
        T x, object target) where T:MemberInfo {
    var invokeAttr=(
            x is FieldInfo
                ?BindingFlags.GetField
                :x is PropertyInfo
                    ?BindingFlags.GetProperty
                    :BindingFlags.Default)|
            BindingFlags.NonPublic|
            BindingFlags.Public|
            BindingFlags.Instance;

    return target.GetType().InvokeMember(
        x.Name, invokeAttr, default(Binder), target, null);
}

同様に、値を設定するには:

static void SetValue<T>(
        T x, object target, object value) where T:MemberInfo {
    var args=new object[] { value };
    var invokeAttr=(
            x is FieldInfo
                ?BindingFlags.SetField
                :x is PropertyInfo
                    ?BindingFlags.SetProperty
                    :BindingFlags.Default)|
            BindingFlags.NonPublic|
            BindingFlags.Public|
            BindingFlags.Instance;

    target.GetType().InvokeMember(
        x.Name, invokeAttr, default(Binder), target, args);
}

何をするかを指定していないため、最初の引数として、またはMemberInfo以外を渡すとスローされます。PropertyInfoFieldInfoBindingFlags.Default

于 2015-05-01T14:55:45.653 に答える
3

DLRの使用(コンパイル時にメンバー名がわかっている場合は、十分に単純です):

((dynamic)obj).MyFieldOrPropertyName = myValue;

実行時にメンバー名しかわからない場合は、Marc Gravellが提案したように、FastMemberをお勧めします。

于 2012-10-01T20:19:23.800 に答える