11

これは私の最初の投稿であり、自分の問題に関連するトピックをある程度検索しましたが、適切な答えを見つけるのに多くの問題があります。

私の質問は非常に単純かもしれませんが、答えを出すのはそれほど簡単ではないかもしれないことを私は知っています。存在する場合。

そうは言っても、これは私の場合です。例として、次のように、クラスからプロパティを取得するために使用しているPropertyInfoオブジェクトの配列があります。

public PropertyInfo[] GetProperties (object o)
{
    PropertyInfo[] properties = o.GetType().GetProperties();

    return properties;
}

簡単そうですね。今私の問題はこれです:新しいPropertyInfoオブジェクトを作成し、それを配列に追加する方法は?

ユーザーがPropertyInfoの値を設定したいという他の投稿を見たことがありますが、それは私が必要としているものではありません。必要なのは、新しいPropertyInfoオブジェクトをその場で作成することです。ここで、使用可能なデータはNameTypeのみです。

以前に投稿したテストケースは、私が達成しようとしていることのほんの一例にすぎません。私の本当の最終的な目標は、実際、このクラスに基づいて新しいPropertyInfoを作成できるようにすることです。

public class DynamicClass
{
    public Type ObjectType { get; set; }
    public List<string> PropertyNameList { get; set; }
    public List<Type> PropertyTypeList { get; set; }
}

誰かが私がこれを達成するのを手伝ってくれることを願っています。よろしくお願いします!

編集:GetProperties()メソッドの前にo.GetType()を追加するのを忘れました。イリヤ・イワノフに感謝します!

私は次のようにメソッドSelectPropertiesを呼び出しています:

list = _queriable.Select(SelectProperties).ToList();

メソッドは次のようになります。

private Expression<Func<T, List<string>>> SelectProperties
{
    get
    {
       return value => _properties.Select
                      (
                          prop => (prop.GetValue(value, new object[0]) ?? string.Empty).ToString()
                      ).ToList();
        }
    }

よろしくお願いします、

ルイス


更新

わかりました。280Z28のアドバイスに従い、新しいクラスでPropertyInfoを継承しています。さらに調査を行ったところ、MSDNで、GetValue、SetValue、GetAccessors、GetGetMethod、GetSetMethod、およびGetIndexParametersのメソッドをオーバーライドする必要があることがわかりました。

ただし、パラメーターを使用してbaseを呼び出そうとすると、「抽象メンバーを呼び出せません:'System.Reflection.PropertyInfo.GetAccessesors(bool)'」というエラーが表示されます。パラメータを指定せずにメソッドを呼び出そうとすると、エラーは表示されませんが、それは間違ったアプローチのように感じます。

これは私がこれまでに得たものです:

public override MethodInfo[] GetAccessors(bool nonPublic)
{
   MethodInfo[] temp = base.GetAccessors(nonPublic);

return temp;
}

更新2

わかりました、それはうまくいきませんでした。PropertyInfoまたはPropertyDescriptorのいずれかの派生クラスを実行しようとして数時間後、私はそのアプローチを実行しないことにしました。

代わりに、私は他の投稿を読んで別のアイデアを思いつきました。私の本当の問題は、私が通常読んでプロパティを取得するために使用するクラスが常に同じであるとは限らないという事実にあります。ですから、おそらく本当に必要なのは、動的クラスをその場で作成し、それからプロパティを取得する方法にすぎないことに気づきました。

ExpandoObjectやElasticObjectと呼ばれるものがあることを読みましたが、最終的に解決策を得るためにそれらを問​​題に適用する方法はまだよくわかりません。

さて、私が実際に行っているのはこれです->次のリンクに記載されているソリューションを使用しています:jQuery DataTables Plugin Meets C#。

これは、DBテーブルごとに異なる静的モデル/クラスがあることを前提としています。ただし、私の場合、2つのタイプの列があります。各DBテーブルクラスによって提供される列(別名基本列)と、適応ですでに動的に提供している追加の列です。

例:これがDBテーブルクラスの場合:

public class Table1
{
    public int Field1;
    public string Field2;
    public string Field3;
}

次に、文字列型の「アクション」と呼ばれる追加の列を指定します。次に、DataTableParserクラスの_properties属性に次の情報が含まれている必要があります。

_properties[0] should be int32 Field1
_properties[1] should be String Field2
_properties[2] should be String Field3
_properties[3] should be String Action

そして正直に言うと、それが私に必要なすべてです!それ以上でもそれ以下でもありません!残りはすでに解析しています!

結局、DataTableParserクラスに渡されるオブジェクトとは異なる数の列(提供される)があるため、DataTableの並べ替えとフィルタリング中に常にエラーが発生します。

何か助けてください?ほんとうに必要だ!再度、感謝します。

よろしくお願いします、

ルイス

4

4 に答える 4

10

解決:

さて、基本的に私が行ったことは、動的オブジェクトを作成するために以下のトピックのMyTypeBuilderクラスを(いくつかの適応を加えて)再利用し、そこからIListを取得するメソッドを追加することでした。

リンク:C#でクラスを動的に作成するにはどうすればよいですか?

public class MyObjectBuilder
{
    public Type objType { get; set; }

    public MyObjectBuilder()
    {
        this.objType = null;
    }

    public object CreateNewObject(List<Field> Fields)
    {
        this.objType = CompileResultType(Fields);
        var myObject = Activator.CreateInstance(this.objType);

        return myObject;
    }

    public IList getObjectList()
    {
        Type listType = typeof(List<>).MakeGenericType(this.objType);

        return (IList)Activator.CreateInstance(listType);
    }

    public static MethodInfo GetCompareToMethod(object genericInstance, string sortExpression)
    {
        Type genericType = genericInstance.GetType();
        object sortExpressionValue = genericType.GetProperty(sortExpression).GetValue(genericInstance, null);
        Type sortExpressionType = sortExpressionValue.GetType();
        MethodInfo compareToMethodOfSortExpressionType = sortExpressionType.GetMethod("CompareTo", new Type[] { sortExpressionType });

        return compareToMethodOfSortExpressionType;
    }

    public static Type CompileResultType(List<Field> Fields)
    {
        TypeBuilder tb = GetTypeBuilder();
        ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);

        // NOTE: assuming your list contains Field objects with fields FieldName(string) and FieldType(Type)
        foreach (var field in Fields)
            CreateProperty(tb, field.FieldName, field.FieldType);

        Type objectType = tb.CreateType();
        return objectType;
    }

    private static TypeBuilder GetTypeBuilder()
    {
        var typeSignature = "MyDynamicType";
        var an = new AssemblyName(typeSignature);
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
        TypeBuilder tb = moduleBuilder.DefineType(typeSignature
                            , TypeAttributes.Public |
                            TypeAttributes.Class |
                            TypeAttributes.AutoClass |
                            TypeAttributes.AnsiClass |
                            TypeAttributes.BeforeFieldInit |
                            TypeAttributes.AutoLayout
                            , null);
        return tb;
    }

    private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
    {
        FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);

        PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
        MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
        ILGenerator getIl = getPropMthdBldr.GetILGenerator();

        getIl.Emit(OpCodes.Ldarg_0);
        getIl.Emit(OpCodes.Ldfld, fieldBuilder);
        getIl.Emit(OpCodes.Ret);

        MethodBuilder setPropMthdBldr =
            tb.DefineMethod("set_" + propertyName,
              MethodAttributes.Public |
              MethodAttributes.SpecialName |
              MethodAttributes.HideBySig,
              null, new[] { propertyType });

        ILGenerator setIl = setPropMthdBldr.GetILGenerator();
        Label modifyProperty = setIl.DefineLabel();
        Label exitSet = setIl.DefineLabel();

        setIl.MarkLabel(modifyProperty);
        setIl.Emit(OpCodes.Ldarg_0);
        setIl.Emit(OpCodes.Ldarg_1);
        setIl.Emit(OpCodes.Stfld, fieldBuilder);

        setIl.Emit(OpCodes.Nop);
        setIl.MarkLabel(exitSet);
        setIl.Emit(OpCodes.Ret);

        propertyBuilder.SetGetMethod(getPropMthdBldr);
        propertyBuilder.SetSetMethod(setPropMthdBldr);
    }
}

また、特定のフィールドに関する情報を得るために、このようなFieldクラスを使用しました

public class Field
{
   public string FieldName;
   public Type FieldType;
}

最後に、私はこのメソッドをどこかで見つけました。これにより、人は値をメンバーに設定できます。

public static void SetMemberValue(MemberInfo member, object target, object value)
{
   switch (member.MemberType)
   {
       case MemberTypes.Field:
           ((FieldInfo)member).SetValue(target, value);
           break;
       case MemberTypes.Property:
           ((PropertyInfo)member).SetValue(target, value, null);
           break;
       default:
           throw new ArgumentException("MemberInfo must be if type FieldInfo or PropertyInfo", "member");
   }
}

その後、動的オブジェクトを作成し、それにプロパティを挿入するために、次のことを行いました。

//Creating a List of Fields (string FieldName, Type FieldType) 
List<Field> Fields = new List<Field>();
Fields.Add(new Field { FieldName = "TestName", FieldType = typeof(string) });

//MyObjectBuilder Class
MyObjectBuilder o = new MyObjectBuilder();

//Creating a new object dynamically
object newObj = o.CreateNewObject(Fields);
IList objList = o.getObjectList();

Type t = newObj.GetType();
object instance = Activator.CreateInstance(t);

PropertyInfo[] props = instance.GetType().GetProperties();

int instancePropsCount = props.Count();

for (int i = 0; i < instancePropsCount; ++i)
{
   string fieldName = props[i].Name;
   MemberInfo[] mInfo = null;
   PropertyInfo pInfo = newObj.GetType().GetProperty(fieldName);

   if (pInfo != null)
   {
       var value = pInfo.GetValue(newObj, null);
       mInfo = t.GetMember(fieldName);

       if (value != null && mInfo != null && !string.IsNullOrEmpty(mInfo[0].ToString()))
           SetMemberValue(mInfo[0], instance, value);
   }
   else
   {
       mInfo = t.GetMember(fieldName);

       if (mInfo != null && !string.IsNullOrEmpty(mInfo[0].ToString()))
           SetMemberValue(mInfo[0], instance, null);
   }
}

objList.Add(instance);

このソリューションは、私の最初の質問を少し超えていますが、オブジェクトを動的に作成する方法を示しているため、そのオブジェクトにその場でプロパティを追加できます。

于 2013-04-03T09:14:06.847 に答える
8

PropertyInfo抽象クラスです。Nameとプロパティのみが必要な場合はPropertyType、そこから独自のクラスを派生させて、この情報を提供できます。

これらのインスタンスを利用できる場所は非常に制限されています。あなたをより良くするために、私たちはあなたが作成しようとしているオブジェクトをどのように利用することを計画しているのかを正確に知る必要があります。PropertyInfo

編集:編集GetValueに基づいて、作成しているオブジェクトに固有の方法でメソッドを実装する限り、このクラスを使用できる場合があります。インスタンスで何をしているのDynamicClassか、さらに重要なことに、プロパティ値がどこに格納されるのかが明確ではありません。

public class SimplePropertyInfo : PropertyInfo
{
    private readonly string _name;
    private readonly Type _propertyType;

    public SimplePropertyInfo(string name, Type propertyType)
    {
        if (name == null)
            throw new ArgumentNullException("name");
        if (propertyType == null)
            throw new ArgumentNullException("propertyType");
        if (string.IsNullOrEmpty(name))
            throw new ArgumentException("name");

        _name = name;
        _propertyType = propertyType;
    }

    public override string Name
    {
        get
        {
            return _name;
        }
    }

    public override Type PropertyType
    {
        get
        {
            return _propertyType;
        }
    }

    public override PropertyAttributes Attributes
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    public override bool CanRead
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    public override bool CanWrite
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    public override Type DeclaringType
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    public override Type ReflectedType
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    public override MethodInfo[] GetAccessors(bool nonPublic)
    {
        throw new NotImplementedException();
    }

    public override MethodInfo GetGetMethod(bool nonPublic)
    {
        throw new NotImplementedException();
    }

    public override ParameterInfo[] GetIndexParameters()
    {
        throw new NotImplementedException();
    }

    public override MethodInfo GetSetMethod(bool nonPublic)
    {
        throw new NotImplementedException();
    }

    public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    public override object[] GetCustomAttributes(Type attributeType, bool inherit)
    {
        throw new NotImplementedException();
    }

    public override object[] GetCustomAttributes(bool inherit)
    {
        throw new NotImplementedException();
    }

    public override bool IsDefined(Type attributeType, bool inherit)
    {
        throw new NotImplementedException();
    }
}
于 2013-03-26T16:09:33.887 に答える
0

は抽象クラスなのでPropertyInfo、自分で実装する必要があります。

class MyPropertyInfo : PropertyInfo
{
}

オーバーライドする必要のあるメソッドとプロパティはたくさんありますが、クエリNameType、のみを実行するため、他のメソッドとプロパティを単純throw new InvalidOperationException()にオーバーライドできます。

配列は固定サイズであるため、配列に偽物PropertyInfoを追加することはできませんが、を作成しList<PropertyInfo>、元の配列と偽物PropertyInfoを追加して、を返すことはできますtheList.ToArray()

ただし、これを実装する前に他のオプションを検討します。たとえば、それらの配列から派生せず、代わりにそれらの配列を返す独自のMyPropertyクラスを作成します。PropertyInfo

于 2013-03-26T16:04:21.507 に答える
0

他のいくつかのインスタンスと共通点があるMethod場合、そのようなイベントを処理する最も効率的な方法は、ポリモーフィズムを使用することです。

public abstract class DynamicClass
{
     public virtual Type ObjectType { get; set; }
     public virtual List<string> PropertyNameList { get; set; }
     public virtual List<Type> PropertyTypeList { get; set; }
}

次に、次のことを実行できます。

public class Something : DynamicClass
{
     public override Type ObjectType { get; set; }
     public override List<string> PropertyNameList { get; set; }
     public override List<Type> PropertyTypeList { get; set; }
}

等々...

次に、これらの項目を埋める方法に関する実装を明らかに追加する必要があります。しかし、あなたはただ呼び出すことができます:

DynamicClass[] obj = new DynamicClass[]

obj[0] = new Something();
obj[1] = new SomethingElse();
obj[2] = new AndAnotherSomething();

これは、これを実装するための非常に緩い方法です。しかし、それはあなたが望むようにそれらのフィールドを実装することを可能にするでしょう。次に、それらを配列に入力します。あなたが扱うために。

私はあなたの質問を誤解したかもしれませんが、私はポリモーフィズムを提案するかもしれません。

于 2013-03-26T16:10:31.280 に答える