【问题标题】:Strange Inheritance Issue with C# classesC# 类的奇怪继承问题
【发布时间】:2011-03-13 02:35:45
【问题描述】:
public class DTOa
{
    public int Id { get; set;}
    public string FirstName { get; set;}
}

public class DTOb: DTOa
{
    public string Email { get; set;}
    public string Password { get; set; }
}

public class a
{
    protected DTOa _DTO = new DTOa();
    public int Id
    {
        get
        {
            return _DTO.Id;
        }
        set
        {
            _DTO.Id = value;
        }
    }

    public string FirstName
    {
        get
        {
            return _DTO.FirstName;
        }
        set
        {
            _DTO.FirstName = value;
        }
    }

    public DTOa ToValueObject()
    {
        return _DTO;
    }
}

public class b: a
{
    protected DTOb _DTO = new DTOb();

    public string Email
    {
        get
        {
            return _DTO.Email;
        }

        set
        {
            _DTO.Email = value;
        }
    }

     public string Password
    {
        get
        {
            return _DTO.Password;
        }

        set
        {
            _DTO.Password  = value;
        }
    }

    public DTOb ToValueObject()
    {
        return _DTO;
    }
}

现在让我们执行以下代码

public function test() 
{       
   var a = new a();
   var b = new b();
   b.Id = 100;
   b.FirstName = "Jim";
   b.Email = "email@email.com";
   b.Password = "test";
   Console.WriteLine(b.ToValueObject().Dump());
}

问题是

  1. 我希望 b.ToValueObject 设置了所有属性,但实际上只从 DTOb 类获取属性(所以我的 FirstName 和 Id 属性为 NULL,但我明确设置)

    dump:
    {
            Email: email@email.com,
            Password: test,
            Id: 0
    }
    

任何想法为什么没有设置 ID 和 FirstName 没有设置? DTOb 继承自 DTOa,因此“应该”包括 DTOa 的所有属性。它在代码级别上工作,所以如果我写 console.WriteLine(b.Firstname) - 我会得到正确的值,但是当我调用 ToValueObject() 方法时 - 它被删除了。


好的,这里是工作示例:

public class DTOa : IDTO
{
    public int Id { get; set; }
    public string FirstName { get; set; }
}

public class DTOb : DTOa, IDTO
{

    public string Email { get; set; }
    public string Password { get; set; }
}

public class a
{
    protected IDTO _DTO;

    public a()
    {
        _DTO = new DTOa();
    }

    public int Id
    {
        get
        {
            return (_DTO as DTOa).Id;
        }
        set
        {
            (_DTO as DTOa).Id = value;
        }
    }

    public string FirstName
    {
        get
        {
            return (_DTO as DTOa).FirstName;
        }
        set
        {
            (_DTO as DTOa).FirstName = value;
        }
    }

    public DTOa ToValueObject()
    {
        return (_DTO as DTOa);
    }

}

public class b : a
{
    public b()
    {
        _DTO = new DTOb();
    }

    public string Email
    {
        get
        {
            return (_DTO as DTOb).Email;
        }

        set
        {
            (_DTO as DTOb).Email = value;
        }
    }

    public string Password
    {
        get
        {
            return (_DTO as DTOb).Password;
        }

        set
        {
            (_DTO as DTOb).Password = value;
        }
    }

    public DTOb ToValueObject()
    {
        return _DTO as DTOb;
    }
}

【问题讨论】:

  • dmitry - 如果你很幸运在你的商店里有另一个 oo dvlp 有更多经验,打印这个页面,研究其中的废话,并与他们见面 1/2 小时.在您尝试的前几次尝试中,不可能正确地获得程序的课堂布局 - 这里有一些经典(并且可以理解的新 oo 工程师)设计失误,并且与一个去过那里的真人交谈是任何书都无法击败的或网页。关键 - 15 分钟后,请他们帮助您正确设计。不会在第一次 b/c 时出错,因为它太贵了,而且你永远生活在不可能的代码中。

标签: c# .net inheritance properties


【解决方案1】:

DTOb 继承自 DTOa,因此“应该”包含 DTOa 的所有属性

这是真的,但你也有这个:

public class a
{
    protected DTOa _DTO = new DTOa();
    ...
}

public class b
{
    protected DTOb _DTO = new DTOb();
    ...
}

也就是说,ab 类都在使用“DTO”类的不同实例。实际上,您的编译器应该就b 中的_DTO 向您发出警告,“隐藏”a 中的_DTO 字段。

您要做的是确保两个类都在访问相同的实例。你不能覆盖字段,但你可以覆盖方法,所以这样的东西可能是合适的:

class A
{
    private DTOa _dto = new DTOa();
    protected virtual DTOa GetDTO()
    {
        return _dto;
    }

    public string FirstName
    {
        get { return GetDTO().FirstName; }
        set { GetDTO().FirstName = value; }
    }

    ...
}

class B : A
{
    private DTOb _dto = new DTOb();
    protected virtual DTOa GetDTO()
    {
        return _dto;
    }

    public string Email
    {
        get { return GetDTO().Email; }
        set { GetDTO().Email = value; }
    }

    ...
}

说实话,我不太确定这个“DTO”对象的好处是什么,但以上内容应该会给你你所追求的行为。

【讨论】:

  • 打败我,虽然我要指出你可以覆盖属性。
  • 问题是 B 将同时包含 DTOa 和 DTOb,因此 Id 和 FirstName 字段将重复。
  • @Mark H:是的,但是在B中,DTOa实例基本上不会被使用。如果您不希望额外的实例挂起,您可以对支持字段进行惰性构造。
  • @NickLarsen:这很好,房产可能是一个更“自然”的选择......
  • 该方法不起作用,因为在 B 类中,当您键入 GetDTO().Email = value 时,Email 属性不是 DTOa 类的一部分,而是 DTOb。
【解决方案2】:

我认为在您的 a 和 b 类中复制 DTOa 和 DTOb 的功能没有什么意义。这通常是一种反模式,除非您有特定的理由在值到达 DTOa 之前拦截它们。

无论如何,您可以使用一些泛型来修复您的代码。

public class a<T> where T : DTOa {
    private readonly T _DTO = Activator.CreateInstance<T>();

    protected T DTO { get { return this._DTO; } }

    //properties
}

public class b<T> : a<T> where T : DTOb {
    //NB: Don't override or hide DTO.
    //properties
}


var a = new a<DTOa>();
var b = new b<DTOb>();
b.Id = 100;
b.FirstName = "Jim";
b.Email = "email@email.com";
b.Password = "test";

【讨论】:

    【解决方案3】:

    这是因为您的 b 类创建了自己的 DTO 对象 (protected DTOb _DTO = new DTOb()) 并修改了它,而您的 a 类创建了自己的 DTO 对象 (protected DTOa _DTO = new DTOa()) 并修改了它。

    p>

    您的b 类在任何阶段都不会将其对象传递给a 以进行修改。

    此外,您的 GetValueObject 只会返回该类中的实例。

    要得到你想要的,你需要一个属性,比如:

    public DTOa DTO { get; }
    

    在您的 b 类中将覆盖它,并确保通过此调用设置您的所有设置方法。不过,当您使用 b 时,您必须对它进行一些转换。

    【讨论】:

      【解决方案4】:

      您应该收到有关您的 _DTO 字段和 ToValueObject 方法的警告,该方法隐藏了类 a 中的相应字段/方法。发生的情况是,b 类对象同时具有 DTOa 和 DTOb 对象,都称为 _DTO,a 中的方法引用 DTOa 对象,b 中的方法引用 DTOb 对象。

      我个人认为你这样做是错误的。看起来您正在尝试对用户和具有联系信息的用户进行建模。我建议这里没有真正的继承关系(“is a”),而是“has a”关系——用户有联系信息。如果您以这种方式对其进行建模,您将拥有 UserDTO 和 ContactDTO,并且您的用户对象将同时包含 UserDTO 和 ContactDTO(或对具有 ContactDTO 对象的联系人的引用)。

      【讨论】:

        猜你喜欢
        • 2011-10-19
        • 1970-01-01
        • 2012-08-20
        • 1970-01-01
        • 2012-05-11
        • 1970-01-01
        • 1970-01-01
        • 2012-11-08
        • 1970-01-01
        相关资源
        最近更新 更多