我有以下代码。第一行应该是逗号分隔的标题字符串,剩下的应该是我的集合的内容,可以写入逗号分隔文件。我如何获得价值?
public static List<string> ToListOfStrings<T>(this List<T> items, string sep)
{
var NewList = new List<string>();
//string tempHeaderString = "";
PropertyInfo[] props = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
string s = string.Empty;
foreach (var prop in props)
{
s += prop.Name + sep;
}
NewList.Add(s + System.Environment.NewLine);
foreach (var item in items)
{
string s1 = string.Empty;
var values = new object[props.Length];
for (var i = 0; i < props.Length; i++)
{
s1 += (props[i].GetValue(item, null)).ToString() + sep;
}
NewList.Add(s1 + System.Environment.NewLine);
}
return NewList;
}
我的目标对象T只有字符串作为成员属性。
最佳
乙
答案 0 :(得分:1)
假设您有以下对象:
public class User
{
public string Name { get; set; }
public string Password { get; set; }
}
然后说你有以下代码:
User user = new User { Name = "Pete", Password = "Secret" };
Console.WriteLine(user.ToString());
输出MyNamespace.User, MyAssembly
。您将期望输出什么? Pete
? Secret
?
框架无法决定 你,所以你必须提出自己的解决方案。如果您拥有该类,则可以添加自己的ToString()
实现:
public override string ToString()
{
return Name;
}
但是,如果您不拥有代码,则必须单独为每种类型编写转换器,如果您想要控制哪个属性将为您的CSV提供值。
答案 1 :(得分:0)
据我在评论中理解,只有代码中的问题是属性值的字符串表示。我已经简化了一些代码并创建了一个特殊的方法,您可以在其中放置逻辑以将值转换为字符串,或者如果它是属性中的类型,则可以为类型重载ToString()
方法。
public static IEnumerable<string> ToListOfStrings<T>(this List<T> items, string sep)
{
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
yield return properties.Select(p => p.Name).CreateRow(sep);
foreach (var item in items)
{
yield return properties.Select(p => GetString(p.GetValue(item, null))).CreateRow(sep);
}
}
private static string CreateRow(this IEnumerable<string> values, string separator)
{
return string.Join(separator, values) + System.Environment.NewLine;
}
public static string GetString(object obj)
{
//custom logic to create string from values
return obj.ToString();
}
<强>更新强>
根据您的评论,您还希望显示嵌套对象的属性。这可以这样做:
public static IEnumerable<string> ToListOfStrings<T>(this IEnumerable<T> items, string sep)
{
var properties = typeof(T).GetInstanceProperties();
yield return properties.Select(p => p.Name).CreateRow(sep);
foreach (var item in items)
{
yield return properties.GetValues(item, sep).CreateRow(sep);
}
}
private static string CreateRow(this IEnumerable<string> values, string separator)
{
return values.JoinStrings(separator) + System.Environment.NewLine;
}
private static string JoinStrings(this IEnumerable<string> values, string separator)
{
return string.Join(separator, values);
}
public static PropertyInfo[] GetInstanceProperties(this Type type)
{
return type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
}
private static IEnumerable<string> GetValues(this IEnumerable<PropertyInfo> properties, object obj, string separator)
{
return properties.Select(p => GetString(p.GetValue(obj, null), separator));
}
public static string GetString(object obj, string separator)
{
var type = obj.GetType();
if (type.IsPrimitive || type.IsEnum || type == typeof(string))
return obj.ToString();
var result = obj.GetType().GetInstanceProperties()
.GetValues(obj, separator)
.JoinStrings(separator);
return string.Format("({0})", result);
}
我已将括号中的嵌套对象包装在一起,以显示值的层次结构并保持标题行的一致性。
答案 2 :(得分:0)
我已运行您的代码,它适用于T
的此类属性,这些属性属于基本类型,例如string
或int
。
class Test
{
public string FString { get; set; }
public int FInt { get; set; }
}
/* ... */
List<Test> x = new List<Test>
{
new Test {FString = "A", FInt = 10}, new Test {FString = "B", FInt = 20}
};
输出:
FString;FInt;
A;10;
B;20;
因此代码本身没有问题。
我从您的评论中了解到,有一些自定义类用作T
中字段的类型(例如LINQPad.User.Header
)。正如其他人所提到的,每个类通过重载ToString()
单独负责将自己表示为字符串。只有一个类可以理解如何将其内容转换为有意义的(虽然通常是剥离的)字符串表示。默认是告诉类的名称。这显然不是你所期望的。
您希望以某种方式告诉编译器 您希望将LINQPad.User.Header
表示为字符串。最基本的选项 - 如果您是此类的创建者,则将默认ToString()
替换为自定义实现。另一个解决方案是子类LINQPad.User.Header
并覆盖子类中的ToString()
。仍然不确定这是否可以在您的方案中轻松应用。另一种选择是在CSV创建期间识别出您正在处理的对象是 a LINQPad.User.Header
并相应地写出来(通过使用其公共字段,即。)。
使用Convert.ToString(props[i].GetValue(item,null))
不是一个选项,因为Convert
也不知道 如何将随机类表示为字符串。