c# – 快速创建新的PropertyInfo对象

前端之家收集整理的这篇文章主要介绍了c# – 快速创建新的PropertyInfo对象前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这是我的第一篇文章,虽然我在某个程度上搜索了与我的问题相关的主题,但是找到正确的答案有很多麻烦.

我的问题可能很简单,但我知道答案可能不是那么容易.如果有的话.

就这样说,这是我的例子:作为一个例子,我有一个PropertyInfo对象的数组,我正在使用它从类中获取属性,如下所示:

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

    return properties;
}

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

我看到其他用户想要设置PropertyInfo的值的帖子,但这不是我需要的.我需要的是快速创建一个新的PropertyInfo对象,其中唯一可用的数据是Name和Type.

我之前发布的测试用例只是我想要实现的一个小例子.
事实上,我真正和最终的目标是能够根据这个类创建一个新的PropertyInfo:

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

我希望有人可以帮助我实现这一点.提前谢谢了!

EDITED:我忘了在GetProperties()方法之前添加o.GetType().感谢Ilya Ivanov!

我正在调用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表具有不同的静态模型/类.然而,在我的情况下,我将有两种类型的列:每个DB表类提供的列(也称为基本列),然后是我在自适应中动态提供的其他列.

例如:如果这是DB表类:

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

然后我提供一个名为“Action”的字符串类型的额外列,然后在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过程中总会出现错误.

请帮忙吗我真的需要它!再次感谢.

最好的祝福,

路易斯

解决方法

解:

好的,基本上我所做的是从下面的主题重用MyTypeBuilder类(有一些修改),以便创建一个动态对象,并添加一个方法获取IList.

链接How to dynamically create a class in 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,null);
        MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName,MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,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],null);
   }
}

objList.Add(instance);

这个解决方案有点超出了我的初始问题,但它显示了如何动态创建一个对象,因此允许我们在该对象上快速添加属性.

猜你在找的C#相关文章