想要使用具有 '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(面向对象编程)中,继承和父子的概念具有误导性。这不像 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 约束并把它作为一个扩展 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 的调用中推断类型。