我正在尝试为复合控件构建一个通用的祖先.最初的想法看起来像这样:
type
TCompositeControl<TControl1: TControl; TControl2: TControl> = class(TWinControl)
private
FControl1,
FControl2: TControl;
public
constructor Create(AOwner: TComponent); override;
end;
TLabelAndEdit = TCompositeControl<TLabel, TEdit>; // simple example for illustration only
constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FControl1 := TControl1.Create(Self);
FControl2 := TControl2.Create(Self);
end;
Run Code Online (Sandbox Code Playgroud)
您可能已经知道,这将触发编译器错误E2568:无法在类型参数声明中创建没有CONSTRUCTOR约束的新实例.constructor然而,添加约束并没有帮助,因为它意味着无参数构造函数.
转换模板以TControl使代码可编译:
...
FControl1 := TControl(TControl1).Create(Self);
...
Run Code Online (Sandbox Code Playgroud)
...但它会在运行时导致访问冲突.
一个可能有用的黑客是通过RTTI调用构造函数,但我认为这是一个相当脏的解决方案.
另一个基本上有效的黑客是使用类类型变量作为中间体:
type
TControlClass = class of TControl;
constructor TCompositeControl<TControl1,TControl2>.Create(AOwner: TComponent);
var
lCtrlClass1,
lCtrlClass2: TControlClass;
begin
inherited Create(AOwner);
lCtrlClass1 := TControl1;
FControl1 := lCtrlClass1.Create(Self);
lCtrlClass2 := TControl2; …Run Code Online (Sandbox Code Playgroud) delphi generics polymorphism constructor generic-constraints
是否可以使用通用约束,这是一种无界泛型类型?
例如:
public T DoSomething<T>(T dictionary) where T : IDictionary<,>
{
...
}
Run Code Online (Sandbox Code Playgroud)
编辑:为了解释上下文,我想将方法的用法限制为IDictionary,但对于方法本身而言,TKey和TValue究竟是什么并不重要.
给定一个类型的对象,System.Reflection.MethodInfo如何提取通用参数约束?不知怎的,我找不到有关此的合理信息。
我extends在 TypeScript 中使用约束,如下所示:
class Animal {}
class Lion extends Animal {}
class Bear extends Animal {}
class ZooKeeper<T extends Animal> {
constructor(p: T = new Animal()) {
}
}
new ZooKeeper(new Animal());
Run Code Online (Sandbox Code Playgroud)
但p: T = new Animal()包含一个错误:
“动物”类型不能分配给“T”类型。
构造函数 Animal(): 动物
为什么,我该怎么做,以便我可以使用Animal, 代替Animal子类型?
如何指定泛型类型参数只能是协议(或符合该协议的协议),而不能是符合该协议的类?
例如:
import Foundation
@objc protocol MyProtocol {
var name: String { get }
}
@objc protocol MySubProtocol: MyProtocol {
func foo()
}
class MyImplementation: MySubProtocol {
var name: String
init(name: String) {
self.name = name
}
func foo() {
print("Foo! Name: \(self.name)")
}
}
class InterfaceMaker<T: MyProtocol> {
init() {}
func makeInterface() -> NSXPCInterface {
return NSXPCInterface(with: T.self) // Cannot convert value of type 'T.Type' to expected argument type 'Protocol'
}
func getProxy() -> T? {
// Some magic …Run Code Online (Sandbox Code Playgroud) 我正在学习Nhibernate 3.0.在其中一个示例代码示例中,它创建了一个抽象基类实体类:
public abstract class Entity<T> where T : Entity<T>
Run Code Online (Sandbox Code Playgroud)
然后,使Customer实体继承自基Entity类:
public class Customer : Entity<Customer>
Run Code Online (Sandbox Code Playgroud)
我知道这是一个抽象的通用类,它是使用where关键词,以确保类型T是 Entity<T>,这是我感到困惑.
Customer继承自" Entity<Customer>",这个" Entity<Customer>"取" Customer" T,但这Customer不是" Entity<T>".
请帮助我理解这一点,我真的很困惑这个泛型类.
我编写了简单的解析器并希望实现接下来的两个接口:
public interface IResult<TValue, TToken>
where TToken : ITokenizer<IResult<TValue, TToken>, TValue>
{
TToken Tokenizer { get; }
TValue Value { get; }
}
public interface ITokenizer<TResult, TValue>
where TResult : IResult<TValue, ITokenizer<TResult, TValue>>
{
TResult Advance();
}
Run Code Online (Sandbox Code Playgroud)
它还有下一个用途:ITokenizer是一个不可变的类,用于按标记拆分字符串。我们可以调用Advance方法并获取Result:下一个标记和下一个标记器。所以,我想在Result类中存储令牌和标记器,并希望为此添加编译时约束。
现在我在构建这两个接口期间出现编译时错误。
我认为下一个类可以实现具有所有约束的接口:
public class Result : IResult<string, Tokenizer>
{ /* implement interface */}
public class Tokenizer : ITokenizer<Result, string>
{ /* implement interface */}
Run Code Online (Sandbox Code Playgroud)
谁能解释一下出了什么问题?也许为什么这是不可能的,或者如何使此代码正确?
PS 对于我的任务,我可以简单地使用IResult<TValue, TToken>没有任何约束的接口,但是我可以在不丢失约束的情况下实现它吗?
编译器错误:
(3:22) The type …Run Code Online (Sandbox Code Playgroud) 该where T : struct约束仅允许将可接受类型参数的域限制为一组值类型(与包括值和引用类型的类型的超集相比),但似乎也完全禁止可空类型,尽管可空并不一定意味着现代版本的 C# 中的引用类型。
如果我愿意接受的值类型添加了非空一样int?,DateTime?等而拒绝本身可空引用类型(如String),IList的等?是否可以通过这种方式定义约束?如果是怎么办?
我实际上很想学习实现这两种场景:当用作参数的类型必须同时是值和可为空时,以及何时接受可空值类型以及不可空值类型,我认为这些相关足以原谅提及两者,所以我很感激对第二个案例的谦虚评论,并选择一个答案,包括它作为更好的答案(假设另一个答案在其他方面不会真的更好),如果不止一个答案将是提交,我必须选择,但我现在真正需要的是第一种情况(总是需要一个既可以为空又是值类型的类型),我也相信第二种情况会鉴于第一个的知识,非常简单,更不用说坚持将两个问题粘在一起并不是一个好办法,所以我绝对会欣赏并接受只处理第一个案例的答案。
方法的完整签名:
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
Run Code Online (Sandbox Code Playgroud)
我正在学习 lambda 表达式,我有这段代码比较员工列表并按姓名字段对它们进行排序:
List<Employee> employees = new ArrayList<>();
Collections.sort(employees, Comparator.comparing(Employee::getName));
Run Code Online (Sandbox Code Playgroud)
该代码工作正常,但我查看了文档中的 Comparator 功能接口,并且找到了方法“比较()”的签名。
comparing(Function<? super T,? extends U> keyExtractor)
Run Code Online (Sandbox Code Playgroud)
我没有得到比较()的参数。我怎么知道参数接受 lambda 表达式?以及如何解释约束:<? 超级T,?扩展 U> keyExtractor?
我知道 super 是什么意思?在层次继承中必须是类型 T 或以上,并且 ? 在层次继承中也必须是 U 类型及以下类型。但是我们怎么能在我的例子中转述呢?
可以这样解释: ? 继承链中必须是Employees及以上类型,并且继承链中name字段必须是Employees或以下类型?或者 ?必须是类型 Array List 及以上和 ? 必须是类型员工列表及以下?
我想编写一个函数,可以将某些字段添加到 Firebase 消息结构中。有两种不同类型的消息Message和MulticastMessage,它们都包含相同类型的Android和APNS字段,但消息类型之间没有显式声明的关系。
我想我应该能够做到这一点:
type firebaseMessage interface {
*messaging.Message | *messaging.MulticastMessage
}
func highPriority[T firebaseMessage](message T) T {
message.Android = &messaging.AndroidConfig{...}
....
return message
}
Run Code Online (Sandbox Code Playgroud)
但它给出了错误message.Android undefined (type T has no field or method Android)。我也不会写switch m := message.(type)( cannot use type switch on type parameter value message (variable of type T constrained by firebaseMessage))。
我可以写switch m := any(message).(type),但我仍然不确定这是否能达到我想要的效果。
我发现了一些对联合和类型约束感到困惑的人提出的其他问题,但我看不到任何有助于解释为什么这不起作用的答案(也许是因为我试图将它与结构而不是接口一起使用?)或者联合类型约束实际上有什么用处。
generics ×9
c# ×5
constructor ×1
delphi ×1
go ×1
java ×1
java-8 ×1
lambda ×1
nhibernate ×1
nullable ×1
polymorphism ×1
reflection ×1
swift ×1
syntax ×1
typescript ×1
union-types ×1
value-type ×1