使用 DataRow 参数递归调用泛型函数 - MakeGenericMethod 失败

发布于 2024-11-24 16:04:46 字数 4268 浏览 0 评论 0原文

问题是:如果我有 MyConvertDataRowToEntity(DataRow row ) 我从 Parent 类型调用 T 对象,并在内部使用子代类型 Child 调用相同的函数,我应该如何传递 DataRow 参数? 问题是在调用 MakeGenericMethod 的 Invoke 时产生的。 确实将类型更改为DataSet、string和String类型。 运气不好。 (我识别列名称中的子对象 bu 前缀 - PrefixDataColumn )

public static T MyConvertDataRowToEntity<T>(DataRow row ) where T : class, new()
    {

        Type objType = typeof(T);
        Type parentObjType = typeof(T);
        T obj = Activator.CreateInstance<T>(); //hence the new() contsraint
        PropertyInfo propertyGenericType = null;
        object childInstance = null;
        PropertyInfo property;
        string childColumnName = string.Empty ;
        foreach (DataColumn column in row.Table.Columns)
        {
            column.ColumnName = column.ColumnName.Replace("_", "");

            string PrefixDataColumn;
            if (column.ColumnName.IndexOf(".") > (-1))
            {
                ///gets the prefix that is the same as child entity name
                PrefixDataColumn = column.ColumnName.Substring(0, column.ColumnName.IndexOf("."));
                ///the column name in the child
                int length = column.ColumnName.Length - 1;
                int start = column.ColumnName.IndexOf(".") + 1;
                childColumnName = column.ColumnName.Substring(column.ColumnName.IndexOf(".") + 1);
                propertyGenericType = objType.GetProperty(PrefixDataColumn,
                                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.FlattenHierarchy);
                parentObjType = objType;
                if (propertyGenericType != null)
                {
                    Type childType = propertyGenericType.PropertyType;
                    objType = childType;
                    childInstance = Activator.CreateInstance(propertyGenericType.PropertyType);


                    // get the get method for the property
                    MethodInfo method = propertyGenericType.GetGetMethod(true);
                    // get the generic get-method generator 
                    MethodInfo genericHelper = typeof(DataUtil).GetMethod("MyConvertDataRowToEntity", BindingFlags.Public | BindingFlags.Static);

                    List<Type> signature = new List<Type>();
                    // first type parameter is type of target object
                    signature.Add(childType);

                    //next parameters are real types of method arguments
                    foreach (ParameterInfo pi in genericHelper.GetParameters())
                    {
                        signature.Add(pi.ParameterType);
                    }

                    // last parameters are known types of method arguments
                    signature.AddRange(typeof(T).GetGenericArguments());

                    // reflection call to the generic get-method generator to generate the type arguments
                    //MethodInfo constructedHelper = genericHelper.MakeGenericMethod(signature.ToArray());

                    // reflection call to the generic get-method generator to generate the type arguments
                    MethodInfo constructedHelper = genericHelper.MakeGenericMethod(childType );

                    // now call it. The null argument is because it's a static method.
                    object ret = constructedHelper.Invoke(null, new object[] { method });

                   // object myObj =  method.Invoke(null, row);
                   //// property.SetValue(obj, MyConvertDataRowToEntity<childInstance>(DataRow row),null);
                   // childInstance = DataUtil.GetMethod("MyConvertDataRowToEntity").MakeGenericMethod(childType); //MyConvertDataRowToEntity<object>(row); 

                    //childType initializedChild = ;
                    //property.SetValue(obj, value, null);
                    //objType = parentObjType;
                }
                else
                {
                    continue; 
                }
            }


        }
        return obj;
    }

收到此错误: “System.Reflection.RuntimeMethodInfo”类型的对象无法转换为“System.Data.DataRow”类型。

有什么解决办法吗?

附注 尽可能缩小代码范围。

如何使用 desedant 类型递归调用方法并传递 datarow ?

the question is : if i have MyConvertDataRowToEntity(DataRow row )
and I call in with T object from type Parent and inside I call the same function with desendant type Child how should I pass the DataRow parameter ?
The problem is created when Invoke of MakeGenericMethod called.
Did change the type to DataSet , string and String types .
No luck.
(I recognize the children object bu prefix in column names - PrefixDataColumn )

public static T MyConvertDataRowToEntity<T>(DataRow row ) where T : class, new()
    {

        Type objType = typeof(T);
        Type parentObjType = typeof(T);
        T obj = Activator.CreateInstance<T>(); //hence the new() contsraint
        PropertyInfo propertyGenericType = null;
        object childInstance = null;
        PropertyInfo property;
        string childColumnName = string.Empty ;
        foreach (DataColumn column in row.Table.Columns)
        {
            column.ColumnName = column.ColumnName.Replace("_", "");

            string PrefixDataColumn;
            if (column.ColumnName.IndexOf(".") > (-1))
            {
                ///gets the prefix that is the same as child entity name
                PrefixDataColumn = column.ColumnName.Substring(0, column.ColumnName.IndexOf("."));
                ///the column name in the child
                int length = column.ColumnName.Length - 1;
                int start = column.ColumnName.IndexOf(".") + 1;
                childColumnName = column.ColumnName.Substring(column.ColumnName.IndexOf(".") + 1);
                propertyGenericType = objType.GetProperty(PrefixDataColumn,
                                    BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.FlattenHierarchy);
                parentObjType = objType;
                if (propertyGenericType != null)
                {
                    Type childType = propertyGenericType.PropertyType;
                    objType = childType;
                    childInstance = Activator.CreateInstance(propertyGenericType.PropertyType);


                    // get the get method for the property
                    MethodInfo method = propertyGenericType.GetGetMethod(true);
                    // get the generic get-method generator 
                    MethodInfo genericHelper = typeof(DataUtil).GetMethod("MyConvertDataRowToEntity", BindingFlags.Public | BindingFlags.Static);

                    List<Type> signature = new List<Type>();
                    // first type parameter is type of target object
                    signature.Add(childType);

                    //next parameters are real types of method arguments
                    foreach (ParameterInfo pi in genericHelper.GetParameters())
                    {
                        signature.Add(pi.ParameterType);
                    }

                    // last parameters are known types of method arguments
                    signature.AddRange(typeof(T).GetGenericArguments());

                    // reflection call to the generic get-method generator to generate the type arguments
                    //MethodInfo constructedHelper = genericHelper.MakeGenericMethod(signature.ToArray());

                    // reflection call to the generic get-method generator to generate the type arguments
                    MethodInfo constructedHelper = genericHelper.MakeGenericMethod(childType );

                    // now call it. The null argument is because it's a static method.
                    object ret = constructedHelper.Invoke(null, new object[] { method });

                   // object myObj =  method.Invoke(null, row);
                   //// property.SetValue(obj, MyConvertDataRowToEntity<childInstance>(DataRow row),null);
                   // childInstance = DataUtil.GetMethod("MyConvertDataRowToEntity").MakeGenericMethod(childType); //MyConvertDataRowToEntity<object>(row); 

                    //childType initializedChild = ;
                    //property.SetValue(obj, value, null);
                    //objType = parentObjType;
                }
                else
                {
                    continue; 
                }
            }


        }
        return obj;
    }

Getting this error :
Object of type 'System.Reflection.RuntimeMethodInfo' cannot be converted to type 'System.Data.DataRow'.

Is there any solution for this ?

p.s.
Narrowed down the code as much as i could.

How can I invoke the Method recursivly with desedant types and pass datarow ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

痴意少年 2024-12-01 16:04:46

错误的原因是您正在调用 MyConvertDataRowToEntity,但随后传入属性的 getaccessor methodinfo 作为参数,而不是仅包含这些字段的数据行。

如果您想继续当前使用的代码处理逻辑,则需要构造一个新的数据行,其中包含从列名称开头删除的所需字段(带有前缀和“.”)。

或者,您可以创建一个辅助方法,接受列名、源对象,并且它只是更新值。

static void UpdateItemProperty<T>(T item, string columnName, object rowValue) {
  var prefixColumn=columnName.IndexOf(".")==-1 ? columnName : columnName.Split(".")[0];
  var pi = typeof(T).GetProperty(prefixColumn // Add your binding flags);
  // if pi==null then there is an error...
  if (column.ColumnName.IndexOf(".") == (-1)) { // No Nesting
    pi.SetValue(item,rowValue);
    return;
  }
  // Nesting 
  var child=pi.GetValue(item);
  if (child==null) {
        // Logic here to get childs type and create an instance then call pi.SetValue with child
  }
  var remainder=string.Join(',',columnName.Split(".").Skip(1).ToArray());
  // make your generic method info for UpdateItemProperty with pi.PropertyType into mi
  mi.Invoke(null,new object[] { child,remainder,value };
}

The reason for the error is because you are calling MyConvertDataRowToEntity<ChildType> but then passing in the getaccessor methodinfo for the property as the parameter instead of a data row containing only those fields.

If you want to continue with the code processing logic you are currently using you would need to construct a new datarow containing the fields you wanted (with the prefix and ".") removed from the start of the column names.

Alternatively you could create a helper method the accepted a column name, the source object and it simply updated the value.

static void UpdateItemProperty<T>(T item, string columnName, object rowValue) {
  var prefixColumn=columnName.IndexOf(".")==-1 ? columnName : columnName.Split(".")[0];
  var pi = typeof(T).GetProperty(prefixColumn // Add your binding flags);
  // if pi==null then there is an error...
  if (column.ColumnName.IndexOf(".") == (-1)) { // No Nesting
    pi.SetValue(item,rowValue);
    return;
  }
  // Nesting 
  var child=pi.GetValue(item);
  if (child==null) {
        // Logic here to get childs type and create an instance then call pi.SetValue with child
  }
  var remainder=string.Join(',',columnName.Split(".").Skip(1).ToArray());
  // make your generic method info for UpdateItemProperty with pi.PropertyType into mi
  mi.Invoke(null,new object[] { child,remainder,value };
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文