动态创建新的PropertyInfo对象

Mad*_*tsu 9 c# reflection object propertyinfo

这是我的第一篇文章,尽管我在某种程度上搜索了与我的问题相关的主题,但我在找到正确的答案时遇到了很多麻烦.

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

话虽如此,这是我的情况:作为一个例子,我有一个PropertyInfo对象数组,我用它来从类中获取属性,如下所示:

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

    return properties;
}
Run Code Online (Sandbox Code Playgroud)

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

我看过其他帖子,用户想要设置PropertyInfo的VALUE,但这不是我需要的.我需要的是动态创建一个新的PropertyInfo对象,其中我唯一可用的数据是NameType.

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

public class DynamicClass
{
    public Type ObjectType { get; set; }
    public List<string> PropertyNameList { get; set; }
    public List<Type> PropertyTypeList { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

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

我正在调用SelectProperties方法,如下所示:

list = _queriable.Select(SelectProperties).ToList();
Run Code Online (Sandbox Code Playgroud)

该方法如下所示:

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

最好的祝福,

路易斯


更新:

好的,所以我遵循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;
}
Run Code Online (Sandbox Code Playgroud)

更新2:

好的,那不行.在尝试使用PropertyInfo或PropertyDescriptor的派生类几个小时之后,我决定不采用这种方法.

相反,我从阅读其他帖子中得到了另一个想法.我真正的问题在于,我通常阅读并用于获取属性的类并不总是相同的.所以我意识到我可能真正需要的只是一种动态创建动态类的方法,然后才能获得属性.

我读到有一个名为ExpandoObject和ElasticObject的东西,虽然我还不知道如何将它们应用到我的问题中以便最终获得解决方案.

好了,我现在正在做的是 - >我一直在使用以下链接中提到的解决方案:jQuery DataTables插件符合C#.

问题是,假设我将为每个数据库表提供不同的静态模型/类.但是在我的例子中,我将有两种类型的列:每个DB表类提供的列(也就是基本列),然后是我在我的改编中动态提供的其他列.

例如:如果这是DB表类:

public class Table1
{
    public int Field1;
    public string Field2;
    public string Field3;
}
Run Code Online (Sandbox Code Playgroud)

然后我提供了一个名为"Action"的字符串类型的额外列,然后在DataTableParser类中,在_properties attribure中应该有以下信息:

_properties[0] should be int32 Field1
_properties[1] should be String Field2
_properties[2] should be String Field3
_properties[3] should be String Action
Run Code Online (Sandbox Code Playgroud)

坦白地说这是所有我需要的!没有更多,没有更少!剩下的我已经解析了!

最后,因为我具有与传递给DataTableParser类的对象不同的列数(提供的),所以在排序和过滤DataTable期间总是会出错.

有什么帮助吗?我真的需要它!再次感谢.

最好的祝福,

路易斯

Mad*_*tsu 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

另外,我使用类似的Field类来获取特定Field的信息

public class Field
{
   public string FieldName;
   public Type FieldType;
}
Run Code Online (Sandbox Code Playgroud)

最后,我发现这个方法允许一个人将值设置为一个成员:

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");
   }
}
Run Code Online (Sandbox Code Playgroud)

之后,我执行以下操作来创建动态对象并在其上插入属性:

//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);
Run Code Online (Sandbox Code Playgroud)

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


Sam*_*ell 6

PropertyInfo是一个抽象类.如果您只需要NamePropertyType属性,则可以从中派生自己的类以提供此信息.

您可以使用这些实例的地方受到极大限制.为了更好地帮助您,我们需要准确了解您计划如何使用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();
    }
}
Run Code Online (Sandbox Code Playgroud)