在父母的方法中使用孩子的财产

时间:2019-04-18 09:51:39

标签: c# oop inheritance

我有很多模型类,其中填充了从Web api服务获取的数据。所有类都共享许多属性,例如创建日期等:

public class Car
    {
        public int CarId { get; set; }
        [Browsable(false)]
        public int CreatedBy { get; set; }
        [DisplayName("Utworzył")]
        public string CreatedByName { get; set; }
        [DisplayName("Data utworzenia")]
        public DateTime CreatedOn { get; set; }
        [Browsable(false)]
        public int? LmBy { get; set; }
        [DisplayName("Zmodyfikował")]
        public string LmByName { get; set; }
        [DisplayName("Data modyfikacji")]
        public DateTime? LmOn { get; set; }
        [Browsable(false)]
        public int TenantId { get; set; }
        [Browsable(false)]
        public string TenantName { get; set; }
    }

所有模型类还具有在db中创建/更新相关实体的方法。例如,“汽车”类的方法是:

public async Task<bool> Add()
        {
            using (var client = new HttpClient())
            {
                string url = Secrets.ApiAddress + $"CreateCar?token=" + Secrets.TenantToken + "&UserId=" + RuntimeSettings.UserId;
                var serializedProduct = JsonConvert.SerializeObject(this);
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
                var result = await client.PostAsync(new Uri(url), content);
                if (result.IsSuccessStatusCode)
                {
                    var rString = await result.Content.ReadAsStringAsync();
                    T _this = JsonConvert.DeserializeObject<T>(rString);
                    this.CarId = _this.CarId;
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public async void Edit()
        {
            using (var client = new HttpClient())
            {
                string url = Secrets.ApiAddress + $"EditCar?token=" + Secrets.TenantToken + "&id={0}&UserId={1}";
                var serializedProduct = JsonConvert.SerializeObject(this);
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
                var result = await client.PutAsync(String.Format(url, this.CarId, RuntimeSettings.UserId), content);
            }
        }

所以我认为最好为所有其他模型派生一个模型类。它具有所有共享属性:

public abstract class Entity<T>
    {
        [Browsable(false)]
        public int CreatedBy { get; set; }
        [DisplayName("Utworzył")]
        public string CreatedByName { get; set; }
        [DisplayName("Data utworzenia")]
        public DateTime CreatedOn { get; set; }
        [Browsable(false)]
        public int? LmBy { get; set; }
        [DisplayName("Zmodyfikował")]
        public string LmByName { get; set; }
        [DisplayName("Data modyfikacji")]
        public DateTime? LmOn { get; set; }
        [Browsable(false)]
        public int TenantId { get; set; }
        [Browsable(false)]
        public string TenantName { get; set; }
    }

它的用法如下:

public class Car : Entity<Car>
    {
        public int CarId { get; set; }
    }

我的问题在于方法。如果我将它们保留在父类中(因为共享了90%的逻辑,所以不为每个子代创建它们),我不能仅在父代的方法中使用子代的id属性(CarId),因为此类属性在父代中不存在:

public async Task<bool> Add()
        {
            using (var client = new HttpClient())
            {
                string url = Secrets.ApiAddress + $"Create{typeof(T).Name}?token=" + Secrets.TenantToken + "&UserId=" + RuntimeSettings.UserId;
                var serializedProduct = JsonConvert.SerializeObject(this);
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
                var result = await client.PostAsync(new Uri(url), content);
                if (result.IsSuccessStatusCode)
                {
                    var rString = await result.Content.ReadAsStringAsync();
                    T _this = JsonConvert.DeserializeObject<T>(rString);
                    this.CarId = _this.CarId; // CarId doesn't exist in parent, it's child's property
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }

        public async void Edit()
        {
            using (var client = new HttpClient())
            {
                string url = Secrets.ApiAddress + $"Edit{typeof(T).Name}?token=" + Secrets.TenantToken + "&id={0}&UserId={1}";
                var serializedProduct = JsonConvert.SerializeObject(this);
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
                var result = await client.PutAsync(String.Format(url, this.CarId, RuntimeSettings.UserId), content); // CarId doesn't exist in parent, it's child's property
            }
        }

如果我使用更多的通用ID属性名称(用ID代替CarId)会更简单,但是假设我必须坚持使用自定义名称(“ CarId”,“ EmployeeId”),我有什么选择?

也许我可以在父级中创建通用ID属性,并在继承时以某种方式将其与子级的适当ID字段绑定?

4 个答案:

答案 0 :(得分:0)

这种方式:

public abstract class Entity
{
    [Browsable(false)]
    public int CreatedBy { get; set; }
    [DisplayName("Utworzył")]
    public string CreatedByName { get; set; }
    [DisplayName("Data utworzenia")]
    public DateTime CreatedOn { get; set; }
    [Browsable(false)]
    public int? LmBy { get; set; }
    [DisplayName("Zmodyfikował")]
    public string LmByName { get; set; }
    [DisplayName("Data modyfikacji")]
    public DateTime? LmOn { get; set; }
    [Browsable(false)]
    public int TenantId { get; set; }
    [Browsable(false)]
    public string TenantName { get; set; }
}


public class Car : Entity
{
    public int CarId { get; set; }
}

然后,您必须覆盖要处理的每个不同类的方法。

答案 1 :(得分:0)

建立一个abstract超类的想法是绝对好的。但是,它不必是通用的。它应该只包含所有常见行为。说了这一点,您的Entitity类还应该具有abstract ID属性:

public abstract class Entity
{
    [Browsable(false)]
    public int CreatedBy { get; set; }
    [DisplayName("Utworzył")]
    public string CreatedByName { get; set; }
    [DisplayName("Data utworzenia")]
    public DateTime CreatedOn { get; set; }
    [Browsable(false)]
    public int? LmBy { get; set; }
    [DisplayName("Zmodyfikował")]
    public string LmByName { get; set; }
    [DisplayName("Data modyfikacji")]
    public DateTime? LmOn { get; set; }
    [Browsable(false)]
    public int TenantId { get; set; }
    [Browsable(false)]
    public string TenantName { get; set; }
    public abstract int Id { get; set; }
}

现在,在实现类中,您可以实现abstract属性,以返回具体的CarId,例如:

public class Car : Entity
{
    public int CarId { get; set; }
    public int Id => CarId;
}

或者,您可以完全忽略CarId类中的Car属性,而仅抽象类中的Id

public class Car : Entity
{
    public int Id get; set; }
}

无论您现在选择这两种方法中的哪一种,都有具有Id成员的Add方法,如下所示:

public async Task<bool> Add()
{
    using (var client = new HttpClient())
    {
        string url = Secrets.ApiAddress + $"Create{this.GetType().Name}?token=" + Secrets.TenantToken + "&UserId=" + RuntimeSettings.UserId;
        var serializedProduct = JsonConvert.SerializeObject(this);
        var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
        var result = await client.PostAsync(new Uri(url), content);
        if (result.IsSuccessStatusCode)
        {
            var rString = await result.Content.ReadAsStringAsync();
            // you don´t need to knoe the actual type, all you need is its Id, so an Entity is just fine
            Entity e = JsonConvert.DeserializeObject(rString);
            this.Id = e.Id; 
            return true;
        }
        else
        {
            return false;
        }
    }
}

答案 2 :(得分:0)

您可能想看看存储库模式。在存储库模式中,使用对实体抽象类中的属性进行基本CRUD操作的基础存储库。然后,创建派生的存储库类,以对实体特定的属性进行操作。 如果您仍然想在模型类中进行操作,则可以执行以下操作。

public abstract class Entity<T>
    {
        [Browsable(false)]
        public int CreatedBy { get; set; }
        [DisplayName("Utworzył")]
        public string CreatedByName { get; set; }
        [DisplayName("Data utworzenia")]
        public DateTime CreatedOn { get; set; }
        [Browsable(false)]
        public int? LmBy { get; set; }
        [DisplayName("Zmodyfikował")]
        public string LmByName { get; set; }
        [DisplayName("Data modyfikacji")]
        public DateTime? LmOn { get; set; }
        [Browsable(false)]
        public int TenantId { get; set; }
        [Browsable(false)]
        public string TenantName { get; set; }
        public virtual void Add(){
//operation using base properties
         }

public class Car : Entity<Car>
    {
        public int CarId { get; set; }
        public override void Add(){
            //do custom operation or call base.Add() or whatever you want
        }
    }

}

答案 3 :(得分:0)

我通过实施小的解决方法解决了该问题。当我将HimBromBeere的建议落实到位时,“编辑”已经起作用。为了使“添加”正常工作,我不得不将Entity类更改为:

public abstract class Entity<T>
    {
        [Browsable(false)]
        public string AddedItem { get; set; }

        public virtual async Task<bool> Add()
        {
            using (var client = new HttpClient())
            {
                string url = Secrets.ApiAddress + $"Create{typeof(T).Name}?token=" + Secrets.TenantToken + "&UserId=" + RuntimeSettings.UserId;
                var serializedProduct = JsonConvert.SerializeObject(this);
                var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
                var result = await client.PostAsync(new Uri(url), content);
                if (result.IsSuccessStatusCode)
                {
                    var rString = await result.Content.ReadAsStringAsync();
                    AddedItem = rString;
                    return true;
                }
                else
                {
                    MessageBox.Show("Serwer zwrócił błąd przy próbie utworzenia rekordu. Wiadomość: " + result.ReasonPhrase);
                    return false;
                }
            }
        }
    }

并将派生类更改为:

public class Car : Entity<Car>
    {
        public async override Task<bool> Add()
        {
            bool x = await base.Add();
            if (x)
            {
                try
                {
                    Car _this = JsonConvert.DeserializeObject<Car>(AddedItem);
                    this.CarId = _this.CarId;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }

                MessageBox.Show("Tworzenie nowego rekordu zakończone powodzeniem!");
                return true;
            }
            else
            {
                return false;
            }
        }
    }

我发现HimBromBeere的答案最有帮助,因此选择他的帖子回答了我的问题。