想要使用具有子类'this'的泛型调用基类



所以我的问题是我想删除复杂对象(如 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(面向对象编程)中,继承和父子的概念具有误导性。不像POCOPropertyEmptySetter<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 时推断出类型。

最新更新