【问题标题】:Downcasting failing from common interface/abstract class通用接口/抽象类的向下转换失败
【发布时间】:2017-08-30 06:03:29
【问题描述】:

我有两个类——Expert 和 Farmer,它们都有一些共同的特征,因此实现了一个抽象类 User。 User 实现了一个接口 IUser。在我的应用程序中,最初填写了公共字段,但随后用户指出他们是否是专家/农民。

此时,我想将当前对象转换为 Expert 或 Farmer 以填充各个独特的字段。我目前的方法是声明IUser user = new Farmer();,然后尝试在适当的时间进行适当的转换:Farmer farmer = user as FarmerExpert expert = user as Expert。但是,转换为 Expert 总是失败,尽管它们都实现了相同的接口和抽象类。

  1. 为什么这个演员会失败?
  2. 使用继承巧妙地解决此问题的正确方法是什么?显然,可以创建在User 抽象类中定义的函数createUser()createFarmer(),或者只是实例化一个User 和一个Farmer 并在两者中填充初始字段,在拆分时采用所需的任何实例,但这些都不是特别优雅。

专家定义:

public partial class Expert : User
    {

        public override Guid Id { get; set; }
        [StringLength(200)]
        public override string Name { get; set; }
        [Key]
        [StringLength(10)]
        public override string phone { get; set; }
        [StringLength(50)]
        public override string state { get; set; }
        [StringLength(50)]
        public override string district { get; set; }
        [StringLength(6)]
        public override string PIN { get; set; }
        public override double geolat { get; set; }
        public override double geolong { get; set; }
        public override int v { get; set; }
        public override int h { get; set; }
        public override string AzureImageURL { get; set; }

        //IParty properties
        public override string ServiceUrl { get; set; }
        public override string ChannelId { get; set; }
        public override string PartyChannelAccountId { get; set; }
        public override string PartyChannelAccountName { get; set; }
        public override string BotChannelAccountId { get; set; }
        public override string BotChannelAccountName { get; set; }
        public override string ConversationAccountId { get; set; }
        public override string ConversationAccountName { get; set; }


        //Expert specific properties
        public double price { get; set; }
        public int totalRating { get; set; }
        public int numberOfRating { get; set; }
        public string description { get; set; }
        public string languages { get; set; }
        double _sortIndex = double.Nan
    }

农民的定义:

public partial class Farmer : User, IVisualizable
    {
        //User override fields
        [Key]
        public override Guid Id { get; set; }
        [StringLength(200)]
        public override string Name { get; set; }
        [StringLength(10)]
        public override string phone { get; set; }
        [StringLength(50)]
        public override string state { get; set; }
        [StringLength(50)]
        public override string district { get; set; }
        [StringLength(6)]
        public override string PIN { get; set; }
        public override double geolat { get; set; }
        public override double geolong { get; set; }
        public override int v { get; set; }
        public override int h { get; set; }
        public override string AzureImageURL { get; set; }

        //IParty properties
        public override string ServiceUrl { get; set; }
        public override string ChannelId { get; set; }
        public override string PartyChannelAccountId { get; set; }
        public override string PartyChannelAccountName { get; set; }
        public override string BotChannelAccountId { get; set; }
        public override string BotChannelAccountName { get; set; }
        public override string ConversationAccountId { get; set; }
        public override string ConversationAccountName { get; set; }

        //Farmer specific properties
        [StringLength(12)]
        public string AadhaarNum { get; set; }
        public int cropId { get; set; }
        [StringLength(1)]
        public string acreage { get; set; }

        /// <summary>
        /// Constructor calling base - sets Guid of farmer
        /// </summary>
        public Farmer() : base()
        {

        }

    }

用户定义:

public abstract class User : IUser
    {
        public abstract Guid Id { get; set; }
        public abstract string Name { get; set; }
        public abstract string phone { get; set; }
        public abstract string state { get; set; }
        public abstract string district { get; set; }
        public abstract string PIN { get; set; }
        public abstract double geolat { get; set; }
        public abstract double geolong { get; set; }
        public abstract int v { get; set; }
        public abstract int h { get; set; }
        public abstract string AzureImageURL { get; set; }
        public abstract string ServiceUrl { get; set; }
        public abstract string ChannelId { get; set; }
        public abstract string PartyChannelAccountId { get; set; }
        public abstract string PartyChannelAccountName { get; set; }
        public abstract string BotChannelAccountId { get; set; }
        public abstract string BotChannelAccountName { get; set; }
        public abstract string ConversationAccountId { get; set; }
        public abstract string ConversationAccountName { get; set; }

        /// <summary>
        /// Creates a new User with a new Guid already set.
        /// </summary>
        public User()
        {
            Id = Guid.NewGuid();
        }

    }

IUser的定义:

public interface IUser : IParty
    {
        Guid Id { get; set; }
        string Name { get; set; }
        string state { get; set; }
        string district { get; set; }
        string PIN { get; set; }
        double geolat { get; set; }
        double geolong { get; set; }
        int v { get; set; }
        int h { get; set; }
        string AzureImageURL { get; set; }

    }

谢谢!

【问题讨论】:

  • 请显示失败的具体代码和类定义。至于你的第二个问题,请多描述一下
  • 添加类定义

标签: c# inheritance interface abstract-class downcast


【解决方案1】:

您希望农民如何成为专家?即使如果它们实现了相同的通用接口,它们也是完全不同的。特别是您的班级有一些不常见的成员:

class Expert
{
    public string languages { get; set; }
}
class Farmer
{
    public string AadhaarNum { get; set; }
}

应该如何将languages 转换为AadhaarNum?。那是不可能的,因此没有自动演员表。您必须创建一些自己的演员表或转换,例如

var farmer = new Farmer(expert);

这假设您在两个类中都有一个复制构造函数:

class Farmer
{
    public Farmer(IUser user)
    {
        this.Name = user.Name;
        ...
        // also set the members that exist only on farmer
    }
}

以及相应的Expert-class。

您也可以在抽象基类中引入一些工厂方法。然而,这有一个缺点,即您的基类需要知道所有可能的子类型。因此,引入新的子类会导致更改基类。

【讨论】:

  • 更具体地说,在 C# 中,只有如果名称层次结构表明允许(主格类型),才允许强制转换。不同类型的同名/成员签名不兼容,除非订阅同一个“接口”;与结构类型相比。
  • @user2864740 我不确定这如何适用于答案。没有同名的类。
  • 示例/措辞允许解释为“由于不常见的成员而无法转换”。它使得不可能继承跨越这些成员联合的相同统一类型。因为这些类型只实现了一个严格的子集。
  • 刚刚编辑了添加类定义的问题 - 我想要做的是有一些对象,我可以用它来填充公共成员(在用户中定义),然后能够将该对象转换为农民/专家。在进行转换时,我 100% 确定将填写的唯一字段是两个类之间共有的字段。
  • 使用如上所示的复制构造函数。无需强制转换,只需基于基类/接口的现有实例创建派生类型的新实例。无论如何,我将您的特定需求添加到我的答案中。
猜你喜欢
  • 2012-03-13
  • 2013-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多