Selamat siang. Saya telah banyak bereksperimen dengan .Net 5 dan Generator Sumbernya belakangan ini. Dan tiba-tiba saya mendapat ide tentang bagaimana saya dapat menggunakan Source Generators untuk mengimplementasikan "pengetikan bebek" di C #. Saya tidak bisa begitu saja meninggalkan ide ini. Pada akhirnya, saya akan mengatakan, sesuatu yang murni akamic keluar (saya harap tidak ada yang akan menggunakan ini untuk dijual), tetapi hasilnya cukup menarik. Siapapun yang tertarik untuk meminta potongan!
Saya tidak akan membahas jauh ke dalam implementasinya sendiri. Itu dapat dilihat di repositori, tautannya ada di bawah. Tidak ada yang sulit bagi mereka yang telah mencoba-coba generator, tetapi untuk semua orang, diperlukan artikel yang jauh lebih besar.
Bagaimana cara menggunakannya
Mari kita bayangkan kita memiliki contoh berikut:
public interface ICalculator
{
float Calculate(float a, float b);
}
public class AddCalculator
{
float Calculate(float a, float b);
}
Penting untuk dicatat bahwa AddCalculator
itu tidak diterapkan dengan cara apa pun ICalculator
.
Mereka hanya memiliki tanda tangan yang identik. Jika kami mencoba menggunakannya dengan cara berikut, kami akan gagal:
var addCalculator = new AddCalculator();
var result = Do(addCalculator, 10, 20);
float Do(ICalculator calculator, float a, float b)
{
return calculator.Calculate(a, b);
}
Kompilator C # akan mengatakan yang berikut:
Argument type 'AddCalculator' is not assignable to parameter type 'ICalculator'
Dan dia akan benar. Tetapi karena tanda tangannya AddCalculator
benar-benar sama ICalculator
dan kami benar-benar ingin melakukan ini, solusinya mungkin mengetik bebek yang tidak berfungsi di C #. Di sinilah paket nuget berguna DuckInterface
. Yang perlu Anda lakukan adalah menginstalnya dan mengubah sedikit tanda tangan kami. Mari kita mulai dengan antarmuka dengan menambahkan atribut ke dalamnya Duckable
:
[Duckable]
public interface ICalculator
{
float Calculate(float a, float b);
}
Do
. ICalculator
DICalculator
. DICalculator
DuckInterface
.
DICalculator
ICalculator
. IDE. DICalculator
.
:
var addCalculator = new AddCalculator();
var result = Do(addCalculator, 10, 20);
float Do(DICalculator calculator, float a, float b)
{
return calculator.Calculate(a, b);
}
. .
. Duckable
"" . , ICalculator
:
public partial class DICalculator : ICalculator
{
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private readonly Func<float, float, float> _Calculate;
[System.Diagnostics.DebuggerStepThrough]
public float Calculate(float a, float b)
{
return _Calculate(a, b);
}
}
duckable . :
var result = Do(addCalculator, 10, 20);
Do
DICalculator
, addCalculator
. , DICalculator
:
public partial class DICalculator
{
private DICalculator(global::AddCalculator value)
{
_Calculate = value.Calculate;
}
public static implicit operator DICalculator(global::AddCalculator value)
{
return new DICalculator(value);
}
}
DICalculator
partial class . , :
:
[Duckable]
public interface ICalculator
{
float Zero { get; }
float Value { get; set; }
float Calculate(float a, float b);
}
// ....
public partial class DICalculator : ICalculator
{
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private readonly Func<float> _ZeroGetter;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private readonly Func<float> _ValueGetter;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private readonly Action<float> _ValueSetter;
[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]
private readonly Func<float, float, float> _Calculate;
public float Zero
{
[System.Diagnostics.DebuggerStepThrough] get { return _ZeroGetter(); }
}
public float Value
{
[System.Diagnostics.DebuggerStepThrough] get { return _ValueGetter(); }
[System.Diagnostics.DebuggerStepThrough] set { _ValueSetter(value); }
}
[System.Diagnostics.DebuggerStepThrough]
public float Calculate(float a, float b)
{
return _Calculate(a, b);
}
}
. - duck typing . . ref struct-. , . , where - :
float Do<TCalcualtor>(TCalcualtor calculator, float a, float b)
where TCalcualtor: DICalculator
{
return calculator.Calculate(a, b);
}
zero cost duct typing( , ), , partial class
partial struct
duck . , Do
TCalcualtor
. , , .
. !