[抽象 class] 类型的接口 属性 可以在 C# 中实现为具体的 class 吗?
Can an interface property of type [abstract class] be implemented as a concrete class in C#?
也许是个奇怪的问题。
我有一个 IReservable 接口,它描述了使对象“可保留”的行为。实现它的 class 必须有一个预订列表,以及一些处理 creating/removing 预订的方法。该接口声明了一个保留列表,它是一个抽象的class继承了2个具体的classes;一个用于房间,一个用于椅子(RoomReservation & ChairReservation)。
房间和椅子 class 都实现了 IReservable,并且都将始终只创建一种类型的实例(椅子 -> ChairReservation 和房间 -> RoomReservation)
有没有办法让 IReservable 要求有一个 Reservation 列表,但实现可以决定具体的 Reservation?
在代码中解释:
public interface IReservable
{
ICollection<Reservation> Reservations { get; set; }
// Rest omitted for brevity
}
public class Room : IReservable
{
// Can I make this RoomReservation only?
public ICollection<Reservation> Reservations { get; set; }
}
public class Seat : IReservable
{
// And can I make this ChairReservation only?
public ICollection<Reservation> Reservations { get; set; }
}
没有必要这样做,但我仍然想知道是否真的可以;因为我找不到任何例子。
您可以使用泛型来做到这一点。例如
首先让我们假设您有一些像这样的 类:
public abstract class Reservation { }
public class ChairReservation : Reservation { }
public class RoomReservation : Reservation { }
现在您的界面会变成这样,请注意类型约束以确保预订始终来自 Reservation
:
public interface IReservable<TReservation>
where TReservation : Reservation
{
ICollection<TReservation> Reservations { get; set; }
}
现在您的 Room
和 Seat
类 将是这样的:
public class Room : IReservable<RoomReservation>
{
public ICollection<RoomReservation> Reservations { get; set; }
}
public class Seat : IReservable<ChairReservation>
{
public ICollection<ChairReservation> Reservations { get; set; }
}
我认为这里使用泛型的最佳解决方案如@DavidG 所示
但如果由于某种原因您不能使用泛型,您可以使用 Explicit Interface Implementation
它将是这样的:
public class Room : IReservable
{
IEnumerable<Reservation> reservations;
ICollection<Reservation> IReservable.Reservations { get { return (ICollection<Reservation>)reservations; } set { reservations = value; } }
public ICollection<RoomReservation> Reservations { get { return (ICollection<RoomReservation>)reservations.Cast<RoomReservation>(); } set { reservations = value; } }
}
public class Seat : IReservable
{
IEnumerable<Reservation> reservations;
ICollection<Reservation> IReservable.Reservations { get { return (ICollection<Reservation>)reservations; } set { reservations = value; } }
public ICollection<SeatReservation> Reservations { get { return (ICollection<SeatReservation>)reservations.Cast<SeatReservation>(); } set { reservations = value; } }
}
尽管建议的通用接口技术有效,但我通常很难处理通用接口。接口的优点之一是多态性。通过使用通用接口,您的不同实现将没有通用的基类型,因此您将失去多态性。也就是说,你不能这样做:
IReservable reservable;
reservable = new Room();
reservable = new Seat();
Console.WriteLine(reservable.Reservations.Count);
如果您从未打算利用多态性,那么使用通用接口就足够了(但是,您可能会问自己为什么在这种情况下需要接口)。否则我的建议是使用两种不同的接口,一种用于阅读预订,一种用于阅读和修改:
interface IReservable
{
IEnumerable<Reservation> Reservations { get; }
}
interface IReservable<TReservation> : IReservable
where TReservation : Reservation
{
new ICollection<TReservation> Reservations { get; }
// Reservation methods
}
public class Room : IReservable<RoomReservation>
{
public ICollection<RoomReservation> Reservations { get; }
IEnumerable<Reservation> IReservable.Reservations => Reservations;
}
然后你就可以使用多态了。
也许是个奇怪的问题。
我有一个 IReservable 接口,它描述了使对象“可保留”的行为。实现它的 class 必须有一个预订列表,以及一些处理 creating/removing 预订的方法。该接口声明了一个保留列表,它是一个抽象的class继承了2个具体的classes;一个用于房间,一个用于椅子(RoomReservation & ChairReservation)。
房间和椅子 class 都实现了 IReservable,并且都将始终只创建一种类型的实例(椅子 -> ChairReservation 和房间 -> RoomReservation)
有没有办法让 IReservable 要求有一个 Reservation 列表,但实现可以决定具体的 Reservation?
在代码中解释:
public interface IReservable
{
ICollection<Reservation> Reservations { get; set; }
// Rest omitted for brevity
}
public class Room : IReservable
{
// Can I make this RoomReservation only?
public ICollection<Reservation> Reservations { get; set; }
}
public class Seat : IReservable
{
// And can I make this ChairReservation only?
public ICollection<Reservation> Reservations { get; set; }
}
没有必要这样做,但我仍然想知道是否真的可以;因为我找不到任何例子。
您可以使用泛型来做到这一点。例如
首先让我们假设您有一些像这样的 类:
public abstract class Reservation { }
public class ChairReservation : Reservation { }
public class RoomReservation : Reservation { }
现在您的界面会变成这样,请注意类型约束以确保预订始终来自 Reservation
:
public interface IReservable<TReservation>
where TReservation : Reservation
{
ICollection<TReservation> Reservations { get; set; }
}
现在您的 Room
和 Seat
类 将是这样的:
public class Room : IReservable<RoomReservation>
{
public ICollection<RoomReservation> Reservations { get; set; }
}
public class Seat : IReservable<ChairReservation>
{
public ICollection<ChairReservation> Reservations { get; set; }
}
我认为这里使用泛型的最佳解决方案如@DavidG 所示
但如果由于某种原因您不能使用泛型,您可以使用 Explicit Interface Implementation
它将是这样的:
public class Room : IReservable
{
IEnumerable<Reservation> reservations;
ICollection<Reservation> IReservable.Reservations { get { return (ICollection<Reservation>)reservations; } set { reservations = value; } }
public ICollection<RoomReservation> Reservations { get { return (ICollection<RoomReservation>)reservations.Cast<RoomReservation>(); } set { reservations = value; } }
}
public class Seat : IReservable
{
IEnumerable<Reservation> reservations;
ICollection<Reservation> IReservable.Reservations { get { return (ICollection<Reservation>)reservations; } set { reservations = value; } }
public ICollection<SeatReservation> Reservations { get { return (ICollection<SeatReservation>)reservations.Cast<SeatReservation>(); } set { reservations = value; } }
}
尽管建议的通用接口技术有效,但我通常很难处理通用接口。接口的优点之一是多态性。通过使用通用接口,您的不同实现将没有通用的基类型,因此您将失去多态性。也就是说,你不能这样做:
IReservable reservable;
reservable = new Room();
reservable = new Seat();
Console.WriteLine(reservable.Reservations.Count);
如果您从未打算利用多态性,那么使用通用接口就足够了(但是,您可能会问自己为什么在这种情况下需要接口)。否则我的建议是使用两种不同的接口,一种用于阅读预订,一种用于阅读和修改:
interface IReservable
{
IEnumerable<Reservation> Reservations { get; }
}
interface IReservable<TReservation> : IReservable
where TReservation : Reservation
{
new ICollection<TReservation> Reservations { get; }
// Reservation methods
}
public class Room : IReservable<RoomReservation>
{
public ICollection<RoomReservation> Reservations { get; }
IEnumerable<Reservation> IReservable.Reservations => Reservations;
}
然后你就可以使用多态了。