我正在尝试创建一个扩展方法来将类导出为data-table,在这个方法中我想让用户在datatable中导出具有不同名称的属性,假设类中的属性名是" LoginName将"但是用户希望将其导出为"登录"在数据表中,用户也可以指定多个要重命名的属性。
例如以下是类
public class UserInfo
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string LoginName { get; set; }
public int CompanyID { get; set; }
}
将此类导出为data-table用户将使用像这样的扩展方法
UserInfo us = UserRep.GetUser("userID","Pass");
DataTable userDetails = null;
//Follwing is a pseudo code it could be different in possible manner
userDetails = us.ExportAsDataTable(u=> new {{u.LoginName,"Login"}, {u.CompanyID ,"Company"}});
//Or
userDetails = us.ExportAsDataTable(u=> new { Login = u.LoginName, Company = u.CompanyID});
在ExportAsDataTable下我创建了metod以执行该功能但无法提供正确的表达式来获取用户输入。
public static DataTable ExportAsDataTable<TSource, TProperty>(this TSource instance, Expression<Func<TSource, KeyValuePair<TProperty, string>>> renamePropertyMap)
{
DataTable dataTable = new DataTable();
//Doing export stuff here
return dataTable;
}
//或
public static DataTable ConvertToDataTable<T>(this T instance, Expression<Func<T, object>> renamePropertyMap) where T : EntityBase
{
//Using this method I am able to get the new name of column from expression like this but not getting the original property name
string columnName = (renamePropertyMap.Body as NewExpression).Members[0].Name
/*note :- result in columnName is "Login" which is fine,
but I need to get orignal property name as well, that is
"LoginName", I am unable to get it from expression.*/
DataTable dataTable = new DataTable();
//Doing export stuff here
return dataTable;
}
答案 0 :(得分:2)
我会做这样的事情:
public class FluentBuilder<T>
{
private readonly T _input;
private readonly Dictionary<string, string> _mappings = new Dictionary<string, string>();
public FluentBuilder(T input)
{
_input = input;
}
public FluentBuilder<T> Map(Expression<Func<T, object>> selector, string name)
{
MemberExpression member = selector.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.", selector));
var propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.", selector));
_mappings.Add(propInfo.Name, name);
return this;
}
private string GetName(PropertyInfo prop)
{
string map;
if (_mappings.TryGetValue(prop.Name, out map))
return map;
return prop.Name;
}
public DataTable ToDataTable(string tableName = null)
{
var result = new DataTable(tableName);
foreach (var prop in _input.GetType().GetProperties())
{
result.Columns.Add(GetName(prop));
}
var values = _input.GetType().GetProperties().Select(x => x.GetMethod.Invoke(_input, new object[0])).ToArray();
result.Rows.Add(values);
return result;
}
}
public static class FluentBuilderExtensions
{
public static FluentBuilder<T> SetupWith<T>(this T input)
{
return new FluentBuilder<T>(input);
}
}
class Program
{
public class UserInfo
{
public string MailAddress { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
static void Main(string[] args)
{
var userInfo = new UserInfo()
{
MailAddress = "foo@bar.com",
Username = "foouser",
Password = "barpassword"
};
var dt = userInfo.SetupWith()
.Map(x => x.MailAddress, "address")
.Map(x => x.Username, "user")
.ToDataTable();
}
}
答案 1 :(得分:1)
MoreLINQ已经提供ToDatatable()将IEnumerable结果转换为DataTable。该方法可作为full NuGet package的一部分或作为 source package的一部分提供,您可以将其添加到项目中。
要从UserInfo属性的子集生成DataTable,请在调用Select
之前使用ToDataTable()
,例如:
var table = myUserInfos.Select(us=>new {Login=us.LoginName, Company=us.CompanyID})
.ToDataTable();
如果您只有一个项目,并希望将其转换为单行DataTable:
您可以将其包装在数组中,例如:
var table = new[]{theUser}.Select(us=>new {Login=us.LoginName, Company=us.CompanyID})
.ToDataTable();
答案 2 :(得分:0)
我使用了DataAnnotations
和Reflection
。
您需要添加以下缺少的库的引用。我测试了这段代码并且它正在运行。
using System;
using System.Data;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
class Program
{
static void Main(string[] args)
{
var user = new UserInfo();
var name = GetAttributeFrom<DisplayAttribute>(user, "LoginName").Name;
var dt = objToDataTable(user);
Console.ReadLine();
}
public static DataTable objToDataTable(UserInfo obj)
{
DataTable dt = new DataTable();
UserInfo objU = new UserInfo();
foreach (PropertyInfo info in typeof(UserInfo).GetProperties())
{
dt.Columns.Add(GetAttributeFrom<DisplayAttribute>(objU, info.Name).Name);
}
dt.AcceptChanges();
return dt;
}
public static T GetAttributeFrom<T>(object instance, string propertyName) where T : Attribute
{
var attrType = typeof(T);
var property = instance.GetType().GetProperty(propertyName);
return (T)property.GetCustomAttributes(attrType, false).First();
}
}
public class UserInfo
{
[Display(Name = "ID")]
public int UserID { get; set; }
[Display(Name = "FName")]
public string FirstName { get; set; }
[Display(Name = "LName")]
public string LastName { get; set; }
[Display(Name = "Login")]
public string LoginName { get; set; }
[Display(Name = "Company")]
public int CompanyID { get; set; }
}
答案 3 :(得分:0)
这是我构建扩展方法以将类转换为数据表
的方法public static class EntityExtensions
{
private static readonly string expressionCannotBeNullMessage = "The expression cannot be null.";
private static readonly string invalidExpressionMessage = "Invalid expression.";
public static DataTable ConvertToDataTable<T>(this T instance, Expression<Func<T, object>> proprtiesToSkip = null, Expression<Func<T, object>> proprtiesToRename = null) where T : EntityBase
{
string columnName = "";
string orgPropName;
int counter = 0;
Dictionary<string, string> renameProperties = null;
MemberInfo newName = null;
NewExpression expression = null;
List<string> skipProps = null;
try
{
if (proprtiesToSkip != null )
{
if (proprtiesToSkip.Body is NewExpression)
{
skipProps = new List<string>();
expression = (proprtiesToSkip.Body as NewExpression);
foreach (var cExpression in expression.Arguments)
{
skipProps.Add(GetMemberName(cExpression));
}
}
else
{
throw new ArgumentException("Invalid expression supplied in proprtiesToSkip while converting class to datatable");
}
}
if (proprtiesToRename != null)
{
if (proprtiesToRename.Body is NewExpression)
{
renameProperties = new Dictionary<string, string>();
expression = (proprtiesToRename.Body as NewExpression);
foreach (var cExpression in expression.Arguments)
{
newName = expression.Members[counter];
orgPropName = GetMemberName(cExpression);
renameProperties.Add(orgPropName, newName.Name);
counter++;
}
}
else
{
throw new ArgumentException("Invalid expression supplied in proprtiesToRename while converting class to datatable");
}
}
var properties = instance.GetType().GetProperties().Where(o =>
{
return (skipProps != null && !skipProps.Contains(o.Name, StringComparer.OrdinalIgnoreCase) &&
(o.PropertyType != typeof(System.Data.DataTable) && o.PropertyType != typeof(System.Data.DataSet)));
}).ToArray();
DataTable dataTable = new DataTable();
foreach (PropertyInfo info in properties)
{
columnName = "";
if (renameProperties != null && renameProperties.ContainsKey(info.Name))
{
columnName = renameProperties[info.Name];
}
if (string.IsNullOrEmpty(columnName))
{
columnName = info.Name;
}
dataTable.Columns.Add(new DataColumn(columnName, Nullable.GetUnderlyingType(info.PropertyType) ?? info.PropertyType));
}
object[] values = new object[properties.Length];
for (int i = 0; i < properties.Length; i++)
{
values[i] = properties[i].GetValue(instance);
}
dataTable.Rows.Add(values);
return dataTable;
}
finally
{
renameProperties = null;
newName = null;
expression = null;
skipProps = null;
}
}
private static string GetMemberName(Expression expression)
{
if (expression == null)
{
throw new ArgumentException(expressionCannotBeNullMessage);
}
if (expression is MemberExpression)
{
// Reference type property or field
var memberExpression = (MemberExpression)expression;
return memberExpression.Member.Name;
}
throw new ArgumentException(invalidExpressionMessage);
}
}
像这样调用
class Program
{
static void Main(string[] args)
{
CancelReason ad = new CancelReason();
ad.BusinessLineID = 1;
ad.CancelReasonCodeID = 2;
ad.CancelRefund = "C";
ad.CompanyID = 0;
ad.DBOperation = 1;
ad.Description = "test";
ad.IsActive = "Y";
ad.ReasonCode = "TestCode";
ad.UpdateStamp = new byte[] { 1, 2, 3, 4 };
DataTable dt = ad.ConvertToDataTable(s => new { s.DBOperation, s.BusinessLineID, s.LoggedInUser }, r => new { Refund = r.CancelRefund, Company = r.CompanyID });
}
}