C# 如何从接口访问派生类成员?

C# 如何从接口访问派生类成员?,c#,generics,interface,derived-class,C#,Generics,Interface,Derived Class,我有三节课;实现接口IPProduct的戳记、信件和包裹,它们也有自己的一些功能 public interface IProduct { string Name { get; } int Quantity { get; set; } float Amount { get; } } public class Stamp : IProduct { public string Name { get { return "Stamp"; } } public in

我有三节课;实现接口IPProduct的戳记、信件和包裹,它们也有自己的一些功能

public interface IProduct
{
    string Name { get; }
    int Quantity { get; set; }
    float Amount { get; }
}

public class Stamp : IProduct
{
    public string Name { get { return "Stamp"; } }
    public int Quantity { get; set; }
    public float Amount { get; set; }
    public float UnitPrice { get; set; }
}

public class Letter : IProduct
{
    public string Name { get { return "Letter"; } }
    public int Quantity { get; set; }        
    public float Amount { get; set; }
    public float Weight { get; set; }
    public string Destination { get; set; }
}

public class Parcel : IProduct
{
    public string Name { get { return "Parcel"; } }
    public int Quantity { get; set; }        
    public float Amount { get; set; }
    public float Weight { get; set; }
    public string Destination { get; set; }
    public int Size { get; set; }
}

public static class ShoppingCart
{
    private static List<IProduct> products = new List<IProduct>();
    public static List<IProduct> Items { get { return products; } }
}
我曾想过使用泛型,但在这种情况下,我必须为每种特定类型的产品编写单独的代码

public static class ShoppingCart<T> where T : IProduct
{
    private static List<T> items = new List<T>();
    public static List<T> Items { get { return items; } }
}


ShoppingCart<Stamp>.Items.Add(new Stamp { Quantity = 5, Amount = 10, UnitPrice = 50 });
ShoppingCart<Letter>.Items.Add(new Letter { Destination = "US", Quantity = 1, Weight = 3.5f });

foreach (Stamp s in ShoppingCart<Stamp>.Items)
{
    Console.WriteLine("Name: {0}, Quantity: {1}, Amount: {2}", s.Name, s.Quantity, s.Amount); 
}

foreach (Letter l in ShoppingCart<Letter>.Items)
{
    Console.WriteLine("Name: {0}, Destination: {1}, Weight: {2}", l.Name, l.Destination, l.Weight);      
}

这类问题没有任何设计模式。工厂模式?

无法从派生类访问其他成员的原因是您正在使用列表中的接口,因此只能访问该接口上的属性

一种可能对您有所帮助的模式是双重分派模式

示例如下:

public interface IHandler
{
    void Handle(Stamp stamp);
    void Handle(Letter letter);
    ...
}

public class Handler : IHandler
{
    public void Handle(Stamp stamp)
    {
       // do some specific thing here...
    }
    public void Handle(Letter letter)
    {
       // do some specific thing here...
    }
    ...
}

public interface IProduct
{
    string Name { get; }
    int Quantity { get; set; }
    float Amount { get; }
    void Handle(IHandler handler);
}

public class Stamp : IProduct
{
    public string Name { get { return "Stamp"; } }
    public int Quantity { get; set; }
    public float Amount { get; set; }
    public float UnitPrice { get; set; }
    public void Handle(IHandler handler)
    {
         handler.Handle(this);
    }
}

现在,您可以在处理程序中编程一些特定的功能-我猜您希望计算某种给定的总价,例如数量*单价或重量和目的地查找表…

无法从派生类访问其他成员的原因是您正在使用列表中的接口-因此,您只能访问该接口上的属性

一种可能对您有所帮助的模式是双重分派模式

示例如下:

public interface IHandler
{
    void Handle(Stamp stamp);
    void Handle(Letter letter);
    ...
}

public class Handler : IHandler
{
    public void Handle(Stamp stamp)
    {
       // do some specific thing here...
    }
    public void Handle(Letter letter)
    {
       // do some specific thing here...
    }
    ...
}

public interface IProduct
{
    string Name { get; }
    int Quantity { get; set; }
    float Amount { get; }
    void Handle(IHandler handler);
}

public class Stamp : IProduct
{
    public string Name { get { return "Stamp"; } }
    public int Quantity { get; set; }
    public float Amount { get; set; }
    public float UnitPrice { get; set; }
    public void Handle(IHandler handler)
    {
         handler.Handle(this);
    }
}
您现在可以在处理程序中编程一些特定的功能-我猜您希望计算某种给定的总价,例如数量*单价或重量和目的地查找表

为什么我不能访问附加设置 源的派生类的成员 名单

这是因为,IPProduct接口不知道派生类属性的单价、目的地等

您是否正在尝试添加智能来计算每个派生类对象的数量(戳记、字母、包裹)

然后,我会说,你需要重新设计一点,并使用

为什么我不能访问附加设置 源的派生类的成员 名单

这是因为,IPProduct接口不知道派生类属性的单价、目的地等

您是否正在尝试添加智能来计算每个派生类对象的数量(戳记、字母、包裹)

然后,我会说,你需要重新设计一点,并使用


您无法访问实现接口的类的其他成员,因为您只在项目列表中公开IPProduct。我会将购物车中每个项目的特定列表类型添加到ShoppingCart类中,然后您可以为任何只需要使用IPProduct接口的产品公开购物车中所有产品的序列:

public class ShoppingCart
{
    public IList<Stamp> Stamps { get; }
    public IList<Letter> Letters { get; }
    public IList<Parcel> Parcels { get; }

    public IEnumerable<IProduct> Products
    {
        get
        {
            return this.Stamps.Cast<IProduct>()
                .Concat(this.Letters.Cast<IProduct>())
                .Concat(this.Parcels.Cast<IProduct>());
        }
    }
}

您无法访问实现接口的类的其他成员,因为您只在项目列表中公开IPProduct。我会将购物车中每个项目的特定列表类型添加到ShoppingCart类中,然后您可以为任何只需要使用IPProduct接口的产品公开购物车中所有产品的序列:

public class ShoppingCart
{
    public IList<Stamp> Stamps { get; }
    public IList<Letter> Letters { get; }
    public IList<Parcel> Parcels { get; }

    public IEnumerable<IProduct> Products
    {
        get
        {
            return this.Stamps.Cast<IProduct>()
                .Concat(this.Letters.Cast<IProduct>())
                .Concat(this.Parcels.Cast<IProduct>());
        }
    }
}

这是因为您在foreach循环中将购物车中的每个项目都转换为IPProduct。您需要做的是:

Foreachi购物车中的产品。项目 { 如果产品是邮票 { var戳记=产品作为戳记; Console.WriteLineName:{0},数量:{1},金额:{2},单价:{3},stamp.Name,stamp.Quantity,stamp.Amount,stamp.UnitPrice; } 否则,如果产品是字母 { var字母=产品字母; Console.WriteLineName:{0},数量:{1},金额:{2},重量:{3},目的地:{4},letter.Name,letter.Quantity,letter.Amount,letter.Weight,letter.Destination; } 否则,如果产品是包裹 { var地块=产品作为地块; Console.WriteLineName:{0},数量:{1},金额:{2},重量:{3},目的地:{4},大小:{5},包裹。名称,包裹。数量,包裹。金额,包裹。重量,包裹。目的地,包裹。大小; } } 或者,这种更现代的语法现在在C中可用,它结合了is运算符和变量声明:

Foreachi购物车中的产品。项目 { 如果产品是邮票 { Console.WriteLineName:{0},数量:{1},金额:{2},单价:{3},stamp.Name,stamp.Quantity,stamp.Amount,stamp.UnitPrice; } 否则,如果产品是字母 { Console.WriteLineName:{0},数量:{1},金额:{2},重量:{3},目的地:{4},letter.Name,letter.Quantity,letter.Amount,letter.Weight,letter.Destination; } 否则,如果产品是包裹 { Console.WriteLineName:{0},数量:{1},金额:{2},重量:{3},目的地:{4},大小:{5},包裹。名称,包裹。数量,包裹。金额,包裹。重量,包裹。目的地,包裹。大小; } } 此外,您正在重复不必要的属性名称、数量和金额。您应该从以下产品派生每个类:

public class Stamp: Product, IProduct
{
    public double UnitPrice { get; set; }
}

public class TransitProduct: Product, IProduct
{
    public double Weight { get; set; }
    public string Destination { get; set; }   
}

public class Letter: TransitProduct, IProduct
{
}

public class Parcel: TransitProduct, IProduct
{
    public double Size { get; set; }
}

这是因为您在foreach循环中将购物车中的每个项目都转换为IPProduct。你需要什么 要做的事情是:

Foreachi购物车中的产品。项目 { 如果产品是邮票 { var戳记=产品作为戳记; Console.WriteLineName:{0},数量:{1},金额:{2},单价:{3},stamp.Name,stamp.Quantity,stamp.Amount,stamp.UnitPrice; } 否则,如果产品是字母 { var字母=产品字母; Console.WriteLineName:{0},数量:{1},金额:{2},重量:{3},目的地:{4},letter.Name,letter.Quantity,letter.Amount,letter.Weight,letter.Destination; } 否则,如果产品是包裹 { var地块=产品作为地块; Console.WriteLineName:{0},数量:{1},金额:{2},重量:{3},目的地:{4},大小:{5},包裹。名称,包裹。数量,包裹。金额,包裹。重量,包裹。目的地,包裹。大小; } } 或者,这种更现代的语法现在在C中可用,它结合了is运算符和变量声明:

Foreachi购物车中的产品。项目 { 如果产品是邮票 { Console.WriteLineName:{0},数量:{1},金额:{2},单价:{3},stamp.Name,stamp.Quantity,stamp.Amount,stamp.UnitPrice; } 否则,如果产品是字母 { Console.WriteLineName:{0},数量:{1},金额:{2},重量:{3},目的地:{4},letter.Name,letter.Quantity,letter.Amount,letter.Weight,letter.Destination; } 否则,如果产品是包裹 { Console.WriteLineName:{0},数量:{1},金额:{2},重量:{3},目的地:{4},大小:{5},包裹。名称,包裹。数量,包裹。金额,包裹。重量,包裹。目的地,包裹。大小; } } 此外,您正在重复不必要的属性名称、数量和金额。您应该从以下产品派生每个类:

public class Stamp: Product, IProduct
{
    public double UnitPrice { get; set; }
}

public class TransitProduct: Product, IProduct
{
    public double Weight { get; set; }
    public string Destination { get; set; }   
}

public class Letter: TransitProduct, IProduct
{
}

public class Parcel: TransitProduct, IProduct
{
    public double Size { get; set; }
}

谢谢你。你能用C语言提供任何示例/链接或双重分派模式吗?谢谢Codebrain。你能提供C语言中的示例/链接或双分派模式吗?我的问题是,如果你的接口只有成员而不是方法,那么它的意义是什么?您只是在重新定义每个类中的成员。接口是否需要有方法?不,不需要,但通常您使用接口来遵守约定。契约通常是需要通过签署该契约的类来实现的方法。当您在接口中有签名者必须实现的方法时。当涉及到变量本身时,只有变量才有意义创建一个接口?这里有一点John:这些不是真正的变量或方法。它们是属性,是一系列方法getter和setter的语法精确性。有一个commmon i/f来定义它们以用于这种用途是完全合法和有用的——所有impl必须具有的某些属性在给定的上下文中都是有用的。典型的方法是,还有一个实现IPProduct的通用抽象基类BaseProduct,所有产品实现都源于此。我的问题是,如果接口只有成员而不是方法,那么接口的意义何在?您只是在重新定义每个类中的成员。接口是否需要有方法?不,不需要,但通常您使用接口来遵守约定。契约通常是需要通过签署该契约的类来实现的方法。当您在接口中有签名者必须实现的方法时。当涉及到变量本身时,只有变量才有意义创建一个接口?这里有一点John:这些不是真正的变量或方法。它们是属性,是一系列方法getter和setter的语法精确性。有一个commmon i/f来定义它们以用于这种用途是完全合法和有用的——所有impl必须具有的某些属性在给定的上下文中都是有用的。典型的方法是,还要有一个实现IPProduct的通用抽象基类BaseProduct,所有产品实现都是从该基类派生的。我们可以使用类型扩展实现相同的功能吗?是的,但在这种情况下效果是相同的。我们可以使用类型扩展实现相同的功能吗?是的,但在这种情况下效果是相同的