2013-03-26 57 views
9

这是我的第一篇文章,尽管我在某种程度上搜索了与我的问题相关的主题,但我在查找正确答案方面遇到了很多问题。即时创建新的PropertyInfo对象

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

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

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

    return properties; 
} 

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

我已经看到其他帖子,用户想要设置一个PropertyInfo的值,但这不是我所需要的。我需要的是即时创建一个新的PropertyInfo对象,其中唯一可用的数据是名称类型

我之前发布的测试案例仅仅是我试图实现的一个小例子。 我真正和最终目标是什么,其实是为了能够根据这个类来创建一个新的PropertyInfo:

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

我希望有人能帮助我实现这一目标。提前谢谢了!

编辑:我忘了在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表。但是在我的情况,我将有两种类型的列:每一个数据库表类(又名基本列),然后附加列,我在动态适应我已经供应的提供者。

例如:如果数据库表类:

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

然后我提供所谓“动作”类型的字符串的一个额外的列,然后在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 

,老实说这是ALL我所需要的!没有更多,没有什么!剩下的我已经解析了!最后,因为与传递给DataTableParser类的对象有不同数量的列(提供),所以在对数据表进行排序和过滤期间,它总是给出错误。

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

最好的问候,

路易斯

+0

通常你会浏览'aType.GetProperties'。 – 2013-03-26 15:46:51

+1

'typeof(o)'这不会编译。可能你的意思是'o.GetType()。GetProperties()' – 2013-03-26 15:48:53

+2

你打算如何使用这个试图创建的对象? – Andrei 2013-03-26 15:50:39

回答

9

解决方法:

好了,基本上我做了什么被重用从主题的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, 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); 

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

0

由于PropertyInfo是一个抽象类,则必须实现它自己:

class MyPropertyInfo : PropertyInfo 
{ 
} 

有方法和属性一大堆你需要重写但因为你只会查询NameType,你可以在别人根本throw new InvalidOperationException()

添加假PropertyInfo到数组是不可能的,因为数组是固定大小的,但你可以创建一个List<PropertyInfo>,加上原有的阵列和假PropertyInfo它,并返回theList.ToArray()

我认为,虽然实施在此之前的其他选项,例如创建自己的MyPropertyPropertyInfo派生,并返回这些数组来代替。

+0

也许'NotImplementedException'在这里更合适? – Andrei 2013-03-26 16:05:34

+0

@Andrei如果你打算实现它,但尚未完成,请抛出'NotImplementedException'。如果您不打算实现它(例如,您不需要特定实现的功能),请抛出'NotSupportedException'。 – 2013-03-26 16:11:18

+0

@ C.Evenhuis:但是如何在不添加到列表PropertyInfo对象的情况下使用List ?我该如何创建**这些**? – MadGatsu 2013-03-26 16:12:42

4

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(); 
    } 
} 
+0

伴侣我编辑了主题以显示我如何使用IQueryable使用PropertyInfo数组。 – MadGatsu 2013-03-26 16:13:36

+0

@LuisVale你将不得不尝试这个,看看它是否工作。我添加了一个编辑来表明您必须以某种有意义的方式实现'GetValue'方法。 – 2013-03-26 16:22:00

+0

然后我就会这样使用它? List PropertyList = new List (); SimplePropertyInfo property = new SimplePropertyInfo(_name,_type); PropertyList.Add(SimplePropertyInfo); PropertyInfo [] propArray = PropertyList.ToArray(); – MadGatsu 2013-03-26 16:29:13

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

这是实施这是一个非常,非常宽松的方式。但它可以让你实现像你想要的那些领域;然后将它们填充到数组中。为你处理。

我可能误解了你的问题,但我可能会建议多态性