动态创建新PropertyInfo对象 [英] Create new PropertyInfo object on the fly

查看:1033
本文介绍了动态创建新PropertyInfo对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的第一个职位,虽然我已经搜查与我的问题在一定程度上的话题,我有很多的麻烦找合适的答案。

This is my very first post, and although I have searched in topics related to my issue to some extent, I'm having a lot of trouble finding the proper answer.

我的问题可能很简单,但我知道,答案可能不会那么容易放弃。如果任何存在于所有的

My question may be very simple, but I'm aware that the answer might not be so easy to give. If any exists at all.

有了这样说,这是我的情况:作为一个例子,我的PropertyInfo对象,我使用得到的数组性能从类,像这样的:

With that being said, this is my case: as an example, I have an array of PropertyInfo objects, which I am using to get the properties from a class, like this:

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

    return properties;
}



看起来很容易,不是吗?现在我的问题是这样的:如何以创建一个新的PropertyInfo对象,并将其添加到阵列

Looks easy, right? Now my problem is this: how to create a new PropertyInfo object and add it to the array?

我所看到的,用户希望其他职位?设置的PropertyInfo的价值,但是这不是我所需要的。我需要的是动态创建一个新的PropertyInfo对象,在那里我有唯一可用的数据是命名键入

I have seen other posts where users want to set the VALUE of a PropertyInfo, but that is not what I need. What I need is to create on the fly a new PropertyInfo object, where the only available data I have is the Name and the Type.

测试情况下,我早些时候公布仅仅是什么,我想实现一个小例子。
我真正和最终目标是什么,其实是为了能够根据这个类来创建一个新的PropertyInfo:

The test case I posted earlier is merely a small example of what I am trying to achieve. My true and final goal is, in fact, to be able to create a new PropertyInfo based on this class:

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



我希望有人能帮助我实现这一目标。提前很多感谢

I hope someone can help me achieve this. Many thanks in advance!

编辑:!我忘了的GetProperties前添加o.GetType()()方法。 !谢谢伊利亚·伊万诺夫

我打电话的方法SelectProperties像这样:

I am calling the method SelectProperties like so:

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



该方法是这样的:

The method looks like this:

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



最好的问候,

Best regards,

路易斯 -

更新

好了,我下面280Z28的建议,我在一个新的类继承的PropertyInfo。我做更多的研究和我MSDN发现,我需要重写以下方法:
的GetValue,的SetValue,GetAccessors,GetGetMethod,GetSetMethod和GetIndexParameters

Ok, so I am following 280Z28's advice and I am inheriting PropertyInfo in a new class. I've done more research and I found in MSDN that I need to override the following methods: GetValue, SetValue, GetAccessors, GetGetMethod, GetSetMethod, and GetIndexParameters.

然而,当我尝试调用基地的参数它给了我错误说我引用不能调用一个抽象成员:System.Reflection.PropertyInfo.GetAccessesors(布尔)'。如果我尝试调用该方法不带任何参数,它不会出现任何错误,但我觉得这是错误的做法。

However, when I try to call base with the parameters it gives me error saying and I quote "Cannot call an abstract member: 'System.Reflection.PropertyInfo.GetAccessesors(bool)'". If I try to call the method without any parameters, it does not show up any error but I feel like that is the wrong approach.

这是我得到了什么到目前为止:

This is what I've got so far:

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

return temp;
}



更新2

好吧,那并没有很好地工作。尝试做任何的PropertyInfo或PropertyDescriptor的派生类中的一些个小时后,我决定不与方法去。

Ok, That did not work well. After some hours of trying to do derived class of either PropertyInfo or PropertyDescriptor, I have decided to not go through with that approach.

相反,我有另外的想法来自阅读其他帖子。我真正的问题在于,我平时阅读和使用来获得属性类并不总是相同的。所以,我意识到我可能真正需要的仅仅是一个方法来创建一个动态类上飞,只有,然后获取属性。

Instead, I had another idea from reading other posts. My true problem lies in the fact that the class I usually read and use to get the properties is not always the same. So I realized what I probably really need is just a way to create a dynamic class on the fly, and only then get the properties.

我看过有这样叫ExpandoObject和ElasticObject的事情,虽然我不太还不知道如何将它们应用到我的问题才能得到最终的解决方案。

I read that there is such a thing called ExpandoObject and ElasticObject, although I don't quite yet know how to apply them to my problem in order to get finally a solution.

好了,现在我真正在做是这样的 - >我一直使用下面的链接中提到的解决方案:的jQuery数据表插件会见C#。

Ok now, what I really AM doing is this -> I have been using the solution mentioned in the following link: jQuery DataTables Plugin Meets C#.

关键是,这里假设我将有不同的静态车型/班每个数据库表。然而,在我而言,我将有两种类型的列:每个数据库表类(又名基本列)提供的关键字,然后附加列,我动态地在我的改编提供已

The thing is, This assumes I will have different static models/classes for each DB table. However in my case, I will have two types of columns: The ones provided by each DB table class (aka basic columns) and then additional columns that I am dynamically supplying already in my adaptation.

例如:如果数据库表类:

For example: if this the DB table class:

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



然后我提供名为类型的动作一个额外的列字符串,然后在DataTableParser类,在_properties attribure应该有如下信息:

And then I supply an extra column called "Action" of type string, then In the DataTableParser class, in the _properties attribure there should be the following information:

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

和说实话这是全部我需要的!仅此而已,无所不及!其余的我已经解析!

And to be honest that is ALL I need! Nothing more, nothing less! The rest I am already parsing!

在最后,是因为我有不同数量比传递到DataTableParser类对象列(提供),它总是给错误排序和过滤数据表中。

In the end, because I have a different number of columns (supplied) than the object passed to the DataTableParser class, it always gives error during Sorting and Filtering the DataTable.

任何帮助吗?我真的需要它!再次感谢。

Any help please? I really need it! Thanks again.

最好的问候,

路易斯 -

推荐答案

解决方案:

Solution:

好了,基本上我所。做的是为了创建一个动态对象重用从主题的MyTypeBuilder类(有一些改动)以下,且增加了一个方法从它那里得到一个IList

Ok, basically what I've done was reusing the MyTypeBuilder class (with some adaptations) from the topic below in order to create a dynamic object and added a method to get an IList from it.

链接: 动态创建在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类像这样有在某一特定领域

Also, I used a Field class like so to have information on a particular Field

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



最后,我发现这个方法的地方,可以让一个人的值设置为会员:

Finally, I found this method somewhere that allows a person to set the value to a Member:

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");
   }
}



之后,我做了以下创建一个动态对象并插入一个属性就可以了:

Afterwards, I did the following to create a dynamic object and insert a property on it:

//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);

这解决方案超越了我最初的问题一点点,但它确实表明如何动态地创建一个对象,从而使我们能够在飞行到该对象添加属性。

This solution goes a little bit beyond my initial question, but it does show how to create an object dynamically, hence allowing us to add properties on the fly to that object.

这篇关于动态创建新PropertyInfo对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆