想要使用具有 'this' of child class 的泛型来调用基础 class
Want to invoke a base class using a generic with 'this' of child class
所以我的问题是我想删除复杂 object 中所有字符串的空值,例如 POCO 和 DTO。我可以做到这一点,但我正在做的方法似乎可以做得更好。所以我认为 Stack Overflow 上有人有更好的方法。
基础Class:
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);
}
}
}
}
Child Class (POCO Object):
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();
}
所以上面的工作,但我希望将它缩短为类似 child 构造函数的内容:
public POCO() : base(this)
呃呃呃。 Visual Studio 不喜欢这个并表示 "Cannot use 'this' in member initializer"
或者让基类中的无参数构造函数做类似
的事情
public PropertyEmptySetter()
{
obj = (child) // Yes I know this does not exist
UpdateStringProperties();
}
我基本上是希望构建所有逻辑,以便继承只知道:"Oh you want this object you are creating RIGHT NOW, gotcha!" 看来我必须在构造函数的范围内执行此操作并且无法绕过它。但我可能只是不知道更简单的方法。我不想在它外面实例化 object 时这样做,我想要这个,所以它只是在 object 在其自身内部和基础 class 内部创建时搭建脚手架。这甚至可能还是我展示的最简单的方法?
最简单的解决方案就是使 PropertyEmptySetter
非通用,因为它不需要。它仅适用于 this
并且每个 class 从它继承的东西都通过 this
只需成为 PropertyEmptySetter
:
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: []
你从基数 classe 派生只是为了在构造函数中创建一个变量,你在没有做任何有用的事情的情况下扔掉了因为 POCO class 中的所有字符串都仍然被初始化,因此空。
如果从 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
约束并把它作为一个扩展 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
的调用中推断类型。
所以我的问题是我想删除复杂 object 中所有字符串的空值,例如 POCO 和 DTO。我可以做到这一点,但我正在做的方法似乎可以做得更好。所以我认为 Stack Overflow 上有人有更好的方法。
基础Class:
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);
}
}
}
}
Child Class (POCO Object):
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();
}
所以上面的工作,但我希望将它缩短为类似 child 构造函数的内容:
public POCO() : base(this)
呃呃呃。 Visual Studio 不喜欢这个并表示 "Cannot use 'this' in member initializer"
或者让基类中的无参数构造函数做类似
的事情public PropertyEmptySetter()
{
obj = (child) // Yes I know this does not exist
UpdateStringProperties();
}
我基本上是希望构建所有逻辑,以便继承只知道:"Oh you want this object you are creating RIGHT NOW, gotcha!" 看来我必须在构造函数的范围内执行此操作并且无法绕过它。但我可能只是不知道更简单的方法。我不想在它外面实例化 object 时这样做,我想要这个,所以它只是在 object 在其自身内部和基础 class 内部创建时搭建脚手架。这甚至可能还是我展示的最简单的方法?
最简单的解决方案就是使 PropertyEmptySetter
非通用,因为它不需要。它仅适用于 this
并且每个 class 从它继承的东西都通过 this
只需成为 PropertyEmptySetter
:
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: []
你从基数 classe 派生只是为了在构造函数中创建一个变量,你在没有做任何有用的事情的情况下扔掉了因为 POCO class 中的所有字符串都仍然被初始化,因此空。
如果从 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
约束并把它作为一个扩展 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
的调用中推断类型。