我试图做的事情:
protocol HasElement {
associatedtype ItemType
func getElement() -> ItemType
func setElement(element: ItemType)
}
class Element {}
class BarElement: Element {}
class Foo: NSObject, HasElement {
typealias ItemType = Element
func getElement() -> Element { ... }
func setElement(element: Element) { ... }
}
class Bar: Foo {
typealias ItemType = BarElement
override func getElement() -> BarElement { ... } // This works.
override func setElement(element: BarElement) { ... } // This fails.
}
错误是:
Method不会覆盖其超类
中的任何方法
如果我尝试使用ItemType:
override func setElement(element: ItemType) { ... } // Still fails.
错误是:
'的ItemType'在此上下文中类型查找是不明确的
有没有办法让这项工作?
答案 0 :(得分:2)
这是一种做你想做的事情的方法:
protocol HasElement {
associatedtype ItemType
func getElement() -> ItemType
func setElement(element: ItemType)
}
class Element {}
class BarElement: Element {}
class Foo: HasElement {
// no need for typealias, the associated type is inferred
func getElement() -> Element { return Element() }
func setElement(element: Element) { }
}
class Bar: Foo {
// no need for typealias, the associated type is inferred
override func getElement() -> BarElement { return BarElement() }
// hide the parent class method
@available(*, unavailable, message: "Use setElement(element: BarElement)")
override func setElement(element: Element) { }
// comply with protocol in this class
func setElement(element: BarElement) { }
}
// can't do this now:
let myElement = Element()
let myBar = Bar()
myBar.setElement(element: myElement) // Error: 'setElement(element: BarElement)' is unavailable: Use setElement(element: BarElement)
答案 1 :(得分:2)
这里的问题不是相关类型,方法输入是contravariant。因此,您不能使用需要子类实例输入的方法覆盖期望给定超类实例输入的方法。
事实上,您可以简单地将代码简化为:
class Element {}
class BarElement : Element {}
class Foo {
func setElement(element: Element) { }
}
class Bar : Foo {
// error: Method does not override any method from its superclass
override func setElement(element: BarElement) { }
}
您无法使用(Element) -> Void
方法覆盖(BarElement) -> Void
方法。如果您考虑在创建Bar
实例并将其向上转换为Foo
时会发生什么,那么这个原因应该是相当明显的。您现在能够将Element
实例传递给期望BarElement
实例的方法,这是非法的。
它适用于getElement
方法的原因是方法输出是协变。因此,使用() -> Element
方法覆盖() -> BarElement
方法是完全合法的,因为即使您将Bar
实例向上转换为Foo
,BarElement
实例也会从getElement
返回{1}}可以自由地转发到Element
。
至于解决方案,它取决于您的确切用例。您可能尝试做的事情根本不需要继承,而是可以将Foo
和Bar
分别与HasElement
相符。< / p>
答案 2 :(得分:0)
这有效:
interface IUser
{
int UserId { get; set; }
string UserName { get; set; }
}
internal IQueryable<T> GetUsers<T>()
where T : IUser, new()
{
var result = from u in db.Users
select new T()
{
UserID = u.ID,
UserName = u.Name
};
return result;
}
使用override func getElement() -> BarElement { ... }
关键字是指函数签名未发生变化(override
仍为BarElement
)。您可以从具有相同函数名,相同参数名和相同返回值类型的超类复制和粘贴函数。
但是
Element
失败,因为更改参数类型(具有相同的参数名称)时。 这种情况是重载而不是覆盖。