delegate相关知识
-
“协变”、“逆变”与Delegate类型转换我在发表了《Delegate如何进行类型转换?》之后又想到了其他一些相关的东西,除了简单地分析如何通过Emit实现EventHandler的类型转换之外,还加上关于Delegate“协变”与“逆变”的一些东西,算是对前一篇文章的完善。目录 一、从Delegate的“协变”与“逆变”说起 二、EventHandler<TEventArgs>是否换一种定义方式更好? 三、“统一的事件注册”能否应用于一般形式? 四、通过Emit实现EventHandler的类型转换 五、最简单的转换方式 一、从Delegate的“协变”与“逆变”说起根据Delegate“协变”与“逆变”的原理,对于两个具有相同声明的两个Delegate(A和B),如果B的所有输入(输入参
-
Delegate如何进行类型转换?我们知道对于两个不具有继承关系的两个类型,如果没有为它们定义转换器,两这之间的类型转换是不允许的,Delegate也是如此。但是有时候我们却希望“兼容”的两种Delegate类型能够进行转换,比较典型的就是表示事件的Delegate。.NET Framework为我们定义了类型EventHandler来表示事件,但是却没有规定事件的Delegate类型是EventHandler的子类。原则上讲,事件可以是任意类型的Delegate,但是我们使用的事件一般具有如下两个共同点:不具有返回类型,或者返回类型为void;有且只有两个输入参数,其一个参数类型为Object,第二个类型是EventArgs的子类。如果事件的类型不是EventHandler的子类,我们是不可以将一个EventHandler对象对事件进行注册的。如果我们能够将EventHandler对象转换成事件对应的类型,那么就可以到达这样的目的:将同一个EventHandler注册给任意的事件。我们举个简单的例子,假设我们具有这样一个需求:对于指定的某
-
C#的delegate简单练习delegate中文的意思为委托。下面Insus.NET在控制台应用程序,简单写一个小例子,作为加强掌握。比如有一个方法:此时,你可以定义一个委托,关键词使用delegate,方法与上面的方法一样,参数个数一样和参数的数据类型也一样: 经过这样一写,你就可以程序中引用了:把方法名当作参数来传入委托的方法内。 现在,我们再添加另外一个方法:结果输出:
-
C#中Delegate和Event以及它们的区别一、Delegate委托可以理解为一个方法签名。 可以将方法作为另外一个方法的参数带入其中进行运算。在C#中我们有三种方式去创建委托,分别如下: public delegate void Print(string str); static void delegatemethod(string str) { Console.WriteLine(str); &n
delegate相关课程
delegate相关教程
- 1.2 基本语法格式 class Student{ var name: String by Delegate()}class Delegate{ operator fun <T> getValue(thisRef: Any?, property: KProperty<*>): T{ ... } operator fun <T> setValue(thisRef: Any?, property: KProperty<*>, value: T){ ... }}属性 name 将它访问器的逻辑委托给了 Delegate 对象,通过 by 关键字对表达式 Delegate() 求值获取这个对象。任何符合属性代理规则都可以使用 by 关键字。属性代理类必须要遵循 getValue(),setValue()方法约定,getValue、setValue方法可以是普通方法也可以是扩展方法,并且是方法是支持运算符重载。如果是 val 修饰的属性只需要具备 getValue() 方法即可。属性代理基本流程就是代理类中的 getValue() 方法包含属性getter访问器的逻辑实现,setValue()方法包含了属性setter访问器的逻辑实现。当属性 name 执行赋值操作时,会触发属性 setter 访问器,然后在setter 访问器内部调用 delegate 对象的 setValue() 方法;执行读取属性 name 操作时,会在 getter 访问器中调用 delegate 对象的 getValue 方法.
- 4. 属性代理背后的原理和源码反编译分析 如果说第三节是揭开属性代理第一层外衣,那么第四节将是揭开最后一层外衣了,你会看到属性代理真正背后的原理,看完你会发现其实挺简单的。不多说先上一个简单例子class Teacher { var name: String by Delegates.notNull() var age: Int by Delegates.notNull()}实际上,以上那行代码是经历了两个步骤:class Teacher { private val delegateString: ReadWriteProperty<Teacher, String> = Delegates.notNull() private val delegateInt: ReadWriteProperty<Teacher, Int> = Delegates.notNull() var name: String by delegateString var age: Int by delegateInt}Kotlin 反编译后 Java 源码:public final class Teacher { // $FF: synthetic field //关键点一 static final KProperty[] $$delegatedProperties = new KProperty[]{(KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Teacher.class), "name", "getName()Ljava/lang/String;")), (KProperty)Reflection.mutableProperty1(new MutablePropertyReference1Impl(Reflection.getOrCreateKotlinClass(Teacher.class), "age", "getAge()I"))}; //关键点二 @NotNull private final ReadWriteProperty name$delegate; @NotNull private final ReadWriteProperty age$delegate; //关键点三 @NotNull public final String getName() { return (String)this.name$delegate.getValue(this, $$delegatedProperties[0]); } public final void setName(@NotNull String var1) { Intrinsics.checkParameterIsNotNull(var1, "<set-?>"); this.name$delegate.setValue(this, $$delegatedProperties[0], var1); } public final int getAge() { return ((Number)this.age$delegate.getValue(this, $$delegatedProperties[1])).intValue(); } public final void setAge(int var1) { this.age$delegate.setValue(this, $$delegatedProperties[1], var1); } public Teacher() { this.name$delegate = Delegates.INSTANCE.notNull(); this.age$delegate = Delegates.INSTANCE.notNull(); }}分析过程:首先, Teacher 类的 name 和 age 属性会自动生成对应的 setter,getter 方法,并且会自动生成对应的name$delegate、age$delegate 委托对象,如代码中标识的关键点二。然后,$$delegatedProperties 的 KProperty 数组中会保存通过 Kotlin 反射出当前 Teacher 类中的中name,age 属性,反射出来每个属性单独对应保存在 KProperty 数组中。然后,在对应属性 setter,getter 方法中是把具体的实现委托给对应的name$delegate、age$delegate 对象的 setValue、getValue 方法来实现的,如代码中标识的关键点三。最后,在 delegate 对象中的 setValue 和 getValue 方法中的传入对应反射出来的属性以及相应的值。
- 5. 自定义属性代理 有以上的介绍,自己写个自定义的属性代理应该很简单了吧。实现一个简单的属性代理最基本架子就是 setValue,getValue 方法且无需实现任何的接口。在 Android 中 SharedPreferences 实际上就是个很好场景,因为它涉及到了属性存储和读取。自定义属性代理实现 Android中SharedPreferences 可以直接实现自带的 ReadWriteProperty 接口,当然也可以自己去写一个类然后去定义相应的 setValue 方法和 getValue 方法。class PreferenceDelegate<T>(private val context: Context, private val name: String, private val default: T, private val prefName: String = "default") : ReadWriteProperty<Any?, T> { private val prefs: SharedPreferences by lazy { context.getSharedPreferences(prefName, Context.MODE_PRIVATE) } override fun getValue(thisRef: Any?, property: KProperty<*>): T { println("setValue from delegate") return getPreference(key = name) } override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { println("setValue from delegate") putPreference(key = name, value = value) } private fun getPreference(key: String): T { return when (default) { is String -> prefs.getString(key, default) is Long -> prefs.getLong(key, default) is Boolean -> prefs.getBoolean(key, default) is Float -> prefs.getFloat(key, default) is Int -> prefs.getInt(key, default) else -> throw IllegalArgumentException("Unknown Type.") } as T } private fun putPreference(key: String, value: T) = with(prefs.edit()) { when (value) { is String -> putString(key, value) is Long -> putLong(key, value) is Boolean -> putBoolean(key, value) is Float -> putFloat(key, value) is Int -> putInt(key, value) else -> throw IllegalArgumentException("Unknown Type.") } }.apply()}
- 8.2 Kotlin 中 DCL 实现 在 Kotlin 中有个天然特性可以支持线程安全 DCL 的单例,可以说也是非常非常简单,就仅仅 3 行代码左右,那就是 Companion Object + lazy 属性代理,一起来看下吧。class KLazilyDCLSingleton private constructor() : Serializable {//private constructor()构造器私有化 fun doSomething() { println("do some thing") } private fun readResolve(): Any {//防止单例对象在反序列化时重新生成对象 return instance } companion object { //通过@JvmStatic注解,使得在Java中调用instance直接是像调用静态函数一样, //类似KLazilyDCLSingleton.getInstance(),如果不加注解,在Java中必须这样调用: KLazilyDCLSingleton.Companion.getInstance(). @JvmStatic //使用lazy属性代理,并指定LazyThreadSafetyMode为SYNCHRONIZED模式保证线程安全 val instance: KLazilyDCLSingleton by lazy(LazyThreadSafetyMode.SYNCHRONIZED) { KLazilyDCLSingleton() } }}//在Kotlin中调用,直接通过KLazilyDCLSingleton类名调用instancefun main(args: Array<String>) { KLazilyDCLSingleton.instance.doSomething()}//在Java中调用public class TestMain { public static void main(String[] args) { //加了@JvmStatic注解后,可以直接KLazilyDCLSingleton.getInstance(),不会打破Java中调用习惯,和Java调用方式一样。 KLazilyDCLSingleton.getInstance().doSomething(); //没有加@JvmStatic注解,只能这样通过Companion调用 KLazilyDCLSingleton.Companion.getInstance().doSomething(); }}注意:建议上面例子中添加 @JvmStatic 注解,Kotlin 这门语言可谓是操碎了心,做的很小心翼翼,为了不让 Java 开发者打破他们的调用习惯,让调用根本无法感知到是 Kotlin 编写,因为外部调用方式和 Java 方式一样。如果硬生生把 Companion 对象暴露给 Java 开发者他们可能会感到一脸懵逼。可能大家对 lazy 和 Companion Object 功能强大感到一脸懵,让我们一起瞅瞅反编译后的 Java 代码你就会恍然大悟了:public final class KLazilyDCLSingleton implements Serializable { @NotNull private static final Lazy instance$delegate; //Companion提供公有全局访问点,KLazilyDCLSingleton.Companion实际上一个饿汉式的单例模式 public static final KLazilyDCLSingleton.Companion Companion = new KLazilyDCLSingleton.Companion((DefaultConstructorMarker)null); public final void doSomething() { String var1 = "do some thing"; System.out.println(var1); } private final Object readResolve() { return Companion.getInstance(); } private KLazilyDCLSingleton() { } static {//注意: 可以看到静态代码块中并不是初始化KLazilyDCLSingleton的instance而是初始化它的Lazy代理对象,说明KLazilyDCLSingleton类被加载了, //但是KLazilyDCLSingleton的instance并没有被初始化,符合懒加载规则,那么什么时候初始化instance这就涉及到了属性代理知识了,下面会做详细分析 instance$delegate = LazyKt.lazy(LazyThreadSafetyMode.SYNCHRONIZED, (Function0)null.INSTANCE); } // $FF: synthetic method public KLazilyDCLSingleton(DefaultConstructorMarker $constructor_marker) { this(); } @NotNull public static final KLazilyDCLSingleton getInstance() { return Companion.getInstance();//这里可以看到加了@JvmStatic注解后,getInstance内部把我们省略Companion.getInstance()这一步,这样一来Java调用者就直接KLazilyDCLSingleton.getInstance()获取单例实例 } //Companion静态内部类实际上也是一个单例模式 public static final class Companion { // $FF: synthetic field static final KProperty[] ?delegatedProperties = new KProperty[]{(KProperty)Reflection.property1(new PropertyReference1Impl(Reflection.getOrCreateKotlinClass(KLazilyDCLSingleton.Companion.class), "instance", "getInstance()Lcom/mikyou/design_pattern/singleton/kts/KLazilyDCLSingleton;"))}; /** @deprecated */ // $FF: synthetic method @JvmStatic public static void instance$annotations() { } @NotNull //这个方法需要注意,最终instance初始化和获取将在这里进行 public final KLazilyDCLSingleton getInstance() { //拿到代理对象 Lazy var1 = KLazilyDCLSingleton.instance$delegate; KProperty var3 = ?delegatedProperties[0]; //代理对象的getValue方法就是初始化instance和获取instance的入口。内部会判断instance是否被初始化过没有就会返回新创建的对象, //初始化过直接返回上一次初始化的对象。所以只有真正调用getInstance方法需要这个实例的时候instance才会被初始化。 return (KLazilyDCLSingleton)var1.getValue(); } private Companion() {//Companion构造器私有化 } // $FF: synthetic method public Companion(DefaultConstructorMarker $constructor_marker) { this(); } }
- 5.1 IOS 项目 ViewController 与组件绑定过程分析 看到上面的运行 Demo,大家有没有在思考一个问题 IOS 项目中的 ViewController 是怎么和 UI 组件绑定在一起的呢?我个人认为这个很重要,换句话说这就是 IOS 开发最基本的套路,如果这个都不弄明白的话,下面 Demo 开发就是云里雾里了,掌握了这个基本套路的话,作为一个 Android 开发者,你基本上就可以在 IOS 项目开发中任意折腾了。在 kotlin 目录下新建一个 KNMapViewController 类,并且它去继承 UIViewController 以及实现 MKMapViewDelegateProtocol 接口,并重写 viewDidLoad () 函数。并且在 viewDidLoad 函数实现 map 地图基本配置。//导入Kotlin以与Objective-C和一些Cocoa Touch框架互操作。import kotlinx.cinterop.*import platform.CoreLocation.CLLocationCoordinate2DMakeimport platform.Foundation.*import platform.MapKit.MKCoordinateRegionMakeimport platform.MapKit.MKCoordinateSpanMakeimport platform.MapKit.MKMapViewimport platform.MapKit.MKMapViewDelegateProtocolimport platform.UIKit.*@ExportObjCClass//注意: @ExportObjCClass注解有助于Kotlin创建一个在运行时可查找的类。class KNMapViewController: UIViewController, MKMapViewDelegateProtocol { @ObjCOutlet //注意: @ObjCOutlet注解很重要,主要是将mMapView属性设置为outlet。这允许您将Main.storyboard中的MKMapview链接到此属性。 lateinit var mMapView: MKMapView constructor(aDecoder: NSCoder) : super(aDecoder) override fun initWithCoder(aDecoder: NSCoder) = initBy(KNMapViewController(aDecoder)) override fun viewDidLoad() { super.viewDidLoad() val center = CLLocationCoordinate2DMake(32.07, 118.78) val span = MKCoordinateSpanMake(0.7, 0.7) val region = MKCoordinateRegionMake(center, span) with(mMapView) { delegate = this@KNMapViewController setRegion(region, true) } }}用 Xcode 打开项目中的 Main.storyboard, 删除原来自动生成一些视图组件 (如果你处于 AppCode 中开发项目,实际上直接在 AppCode 中双击 Main.storyboard 就会自动使用 Xcode 打开当前整个项目,并打开这个项目):给当前空的视图绑定对应 ViewController, 这里是 KNMapViewController:4、在当前空的视图中添加一个 map view 组件并且设置组件的约束条件。右击组件 MKMapView 可以看到黑色对话框,里面 Referencing Outlets 还空的,说明当前 ViewController 没有和 MKMapView 组件绑定:配置 outlet, 这里说下 AppCode 很坑爹地方,需要手动去 source code 中手动配置 outlet,选中 main.storyboard 右击 open as 然后选择打开 source code:在 view 和 viewController 结尾标签之间配置 connection:配置的 code 如下:<connections> <outlet property="mMapView" destination="dest id" id="generate id"/></connections><!--property属性值就是KNMapViewController中的mMapView变量名;destination属性值是一个map view标签中id(可以在subviews标签内的mapView标签中找到id), id属性则是自动生成的,可以按照格式自己之指定一个,只要不出现重复的id即可-->配置结果如下:检验是否绑定成功,回到 main.stroyboard 视图,右击组件查看黑色框是否出现如下绑定关系,出现了则说明配置成功。接着上述配置步骤,就可以回到 AppCode 中运行项目了:
- 11-17 feign - 简化服务调用 Spring Cloud分布式微服务实战
delegate相关搜索
-
daima
damain
dart
dataset
datasource
datediff
datediff函数
datepicker
datetime
db4o
dbi
dcloud
deallocate
debian安装
debugger
debugging
declaration
declarations
declare
decode函数