从普通 interface/abstract class 向下转换失败

Downcasting failing from common interface/abstract class

我有两个 classes - Expert 和 Farmer,它们都有一些共同的特征,因此实现了一个抽象的 class User。用户实现接口 IUser。在我的应用程序中,最初已填写公共字段,但随后用户指示它们是否为 Expert/Farmer。

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

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

专家定义:

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; }

    }

谢谢!

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

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

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

var farmer = new Farmer(expert);

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

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

相应地 Expert-class。

或者,您可以在抽象基础中引入一些工厂方法-class。然而,这有一个缺点,即您的 base-class 需要知道所有可能的子类型。因此引入新的 sub-classes 会导致改变 base-class.