所以我的问题是我想删除复杂对象(如 POCO 和 DTO)中所有字符串的 null。 我可以这样做,但我正在做的方法似乎可以更好。 所以我认为Stack Overflow上的某个人有更好的方法。
基类:
public class PropertyEmptySetter<T> where T : class
{
T obj { get; set; }
public PropertyEmptySetter(T myObj)
{
obj = myObj;
UpdateStringProperties();
}
public PropertyEmptySetter()
{
}
public void UpdateStringProperties()
{
foreach (var prop in obj.GetType().GetProperties().ToList())
{
if (prop.PropertyType == (typeof(string)))
{
if(prop.GetValue(obj) == null)
prop.SetValue(obj, String.Empty);
}
}
}
}
子类(POCO 对象):
public class POCO : PropertyEmptySetter<POCO>
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Purpose { get; set; }
public POCO()
{
var setter = new PropertyEmptySetter<POCO>(this);
}
}
测试它的工作原理:
private static string _s = "";
static void Main(string[] args)
{
var item = new POCO {Id = 1, Name = "Brett", Description = "Me"};
var props = item.GetType().GetProperties();
foreach (var prop in props)
{
_s += "Type: " + prop.Name + "tValue:" + (prop.GetValue(item) ?? "NULL") + Environment.NewLine;
}
Console.WriteLine(_s);
Console.ReadLine();
}
所以上面有效,但我希望将其缩短为类似于子构造函数的内容,说明:
public POCO() : base(this)
呃,呃。 Visual Studio不喜欢这样,并指出"不能在成员初始值设定项中使用'this'"
或者让基中的无参数构造函数做类似的事情
public PropertyEmptySetter()
{
obj = (child) // Yes I know this does not exist
UpdateStringProperties();
}
我基本上希望搭建所有逻辑的脚手架,以便继承只知道:"哦,你想要你现在正在创建的这个对象,明白了! 似乎我必须在构造函数范围内执行此操作,并且无法绕过它。 但我可能只是不知道一种更简单的方法。 我不想在它外面实例化对象时这样做,我想要这个,所以当对象在自身和基类内部创建时,它只是搭建基架。 这甚至可能吗,还是我展示的方法最简单的方法?
最简单的解决方案是使PropertyEmptySetter
非通用的,因为它不需要。它只适用于this
并且从它继承的每个类都通过PropertyEmptySetter
this
传递:
public class PropertyEmptySetter
{
public PropertyEmptySetter()
{
UpdateStringProperties();
}
public void UpdateStringProperties()
{
foreach (var prop in obj.GetType().GetProperties().ToList())
{
if (prop.PropertyType == (typeof(string)))
{
if (prop.GetValue(obj) == null)
prop.SetValue(obj, String.Empty);
}
}
}
}
class POCO : PropertyEmptySetter
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Purpose { get; set; }
}
但是,如果您仍然想使其成为通用,则可以使用静态构建器方法:
class Poco
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Purpose { get; set; }
private Poco() {}
public static Poco CreatePoco()
{
var poco = new Poco();
new PropertyEmptySetter<POCO>(poco);
return poco;
}
}
我认为你缺少C#和.NET的关键技能。
关于您的测试应用程序,首先,在循环中连接字符串总是一个糟糕的主意。字符串在 .NET 中是不可变的,每次连接字符串时,都会创建一个新字符串。请改用StringBuilder
var sb = new StringBuilder();
foreach (var prop in item.GetType().GetProperties())
{
sb.Append("Type: ");
sb.Append(prop.Name);
sb.Append("tValue:");
var value = prop.GetValue(item);
if (value == null)
{
sb.Append(" NULL");
}
else
{
sb.Append(" [");
sb.Append(value);
sb.Append("]");
}
sb.Append(Environment.NewLine);
}
Console.WriteLine(sb.ToString());
其次,你的实现不起作用,你还没有测试你想要避免的东西。如果您尝试这样做:
var item = new POCO {Id = 1, Name = "Brett", Description = null};
你会得到这个:
Type: Id Value: [1]
Type: Name Value: [Brett]
Type: Description Value: NULL
Type: Purpose Value: []
您从基类派生只是为了在构造函数中调用一个变量,而没有做任何有用的事情,因为 POCO 类中的所有字符串都仍在初始化,因此为 null。
如果将其从POCO
构造函数中删除:
public POCO()
{
}
以及来自PropertyEmptySetter<T>
obj
:
public class PropertyEmptySetter<T> where T : class
{
public PropertyEmptySetter()
{
}
public void UpdateStringProperties()
{
foreach (var prop in this.GetType().GetProperties())
{
if (prop.PropertyType == (typeof(string)))
{
if(prop.GetValue(this) == null)
prop.SetValue(this, String.Empty);
}
}
}
}
并像这样使用它:
var item = new POCO {Id = 1, Name = "Brett", Description = null};
item.UpdateStringProperties();
我想你会得到你想要的:
Type: Id Value: [1]
Type: Name Value: [Brett]
Type: Description Value: []
Type: Purpose Value: []
在OOP(面向对象编程)中,继承和父子的概念具有误导性。不像POCO
是PropertyEmptySetter<T>
的孩子,PropertyEmptySetter<T>
是POCO
的父母。 POCO
也是一个PropertyEmptySetter<T>
(更具体地说,是一个PropertyEmptySetter<POCO>
),但PropertyEmptySetter<T>
不一定是POCO
。
如果您不想将 POCO 绑定到PropertyEmptySetter<T>
则可以向PropertyEmptySetter<T>
添加静态方法:
public class PropertyEmptySetter<T> where T : class
{
public void UpdateStringProperties()
{
UpdateStringProperties(this as T);
}
public static T UpdateStringProperties(T obj)
{
if (obj == null)
{
return null;
}
foreach (var prop in obj.GetType().GetProperties())
{
if (prop.PropertyType == (typeof(string)))
{
if(prop.GetValue(obj) == null)
prop.SetValue(obj, String.Empty);
}
}
return obj;
}
}
并且只需:
public class POCO : PropertyEmptySetter<POCO>
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Purpose { get; set; }
}
并像这样使用它:
var item = new POCO {Id = 1, Name = "Brett", Description = null};
PropertyEmptySetter<POCO>.UpdateStringProperties(item);
由于静态方法返回 POCO,因此您可以将其链接起来:
var anotherItem = PropertyEmptySetter<POCO>.UpdateStringProperties(item);
而且,顺便说一下,你没有用它做任何不能在struct
上完成的事情,所以你应该删除class
约束,让它成为一个扩展类:
public static class PropertyEmptySetter
{
public static T UpdateStringProperties<T>(this T obj) where T : class
{
foreach (var prop in obj.GetType().GetProperties())
{
if (prop.PropertyType == (typeof(string)))
{
if(prop.GetValue(obj) == null)
prop.SetValue(obj, String.Empty);
}
}
return obj;
}
}
并像实例方法一样使用UpdateStringProperties
:
var item = new POCO {Id = 1, Name = "Brett", Description = null};
item = item.UpdateStringProperties();
编译器甚至会在调用 UpdateStringProperties
时推断出类型。