Puresharp adalah serangkaian fitur untuk .NET 4.5.2+ / .NET Core 2.1 untuk meningkatkan produktivitas dengan menghasilkan aplikasi yang fleksibel dan efisien.
Puresharp terutama menyediakan alat arsitektur untuk membangun dasar-dasar aplikasi profesional :
Kerangka kerja ini dibagi menjadi 2 bagian :
IPuresharp adalah paket nuget yang didedikasikan untuk menulis ulang rakitan (menggunakan Mono.Cecil ) agar dapat disesuaikan saat runtime. IPuresharp tidak akan menambahkan referensi perpustakaan baru ke rakitan, tetapi hanya menyertakan proses pasca pembuatan untuk secara otomatis menulis ulang rakitan setelah berhasil dibangun.
Install-Package IPuresharp -Version 5.0.5
Ini dapat digunakan secara manual dengan baris perintah untuk mengelola rakitan pihak ketiga
IPuresharp.exe "FullnameToAssembly.dll"
Puresharp adalah paket nuget yang menawarkan berbagai fitur yang berguna untuk merancang arsitektur yang sehat dan produktif. Paket ini juga mencakup semua artileri untuk dengan mudah menangani elemen yang dibawa oleh penulis IL IPuresharp. Paket nuget menambahkan perpustakaan (Puresharp.dll) tanpa ketergantungan lainnya.
Install-Package Puresharp -Version 5.0.5
catatan: Disarankan untuk menginstal paket nuget IPuresharp di semua proyek dan menginstal paket nuget Puresharp hanya di proyek di mana Anda secara eksplisit membutuhkannya.
Alur kerja global DI Container serupa dengan yang lain: menyiapkan komposisi, membuat container, dan membuat instance beberapa komponen dari container.
Contoh antarmuka yang akan dikonfigurasi
public interface IA
{
}
public interface IB
{
}
public interface IC
{
}
Contoh implementasi untuk mengikat antarmuka
public class A : IA
{
public A(IB b, IC c)
{
}
}
public class B : IB
{
public B(IC c, int constant)
{
}
}
public class C : IC
{
}
Buat komposisi
var _composition = new Composition();
Susunan susunan IA, IB, IC masing-masing A, B, C
_composition.Setup<IA>(() => new A(Metadata<IB>.Value, Metadata<IC>.Value), Instantiation.Multiton);
_composition.Setup<IB>(() => new B(Metadata<IC>.Value, 28), Instantiation.Multiton);
_composition.Setup<IC>(() => new C(), Instantiation.Multiton);
Buat wadah dari pengaturan komposisi
var _container = _composition.Materialize();
Buat instance modul IA dari container
using (var _module = _container.Module<IA>())
{
var _ia = _module.Value;
}
catatan: modul adalah siklus hidup IDisposable dan crontrol untuk semua dependensi.
Bagaimana siklus hidup dependensi dikelola? Ketika sebuah modul diatur ke dalam komposisi, mode instantiasi diperlukan dan dapat berupa Singleton (satu instance dengan siklus hidup yang terkait dengan container), Multiton (sebuah instance baru untuk setiap modul dengan siklus hidup yang terkait dengan modul itu sendiri) atau Volatile (selalu merupakan instance baru dengan siklus hidup yang terkait dengan modul pemilik). Kontainer dan Modul keduanya IDisposable untuk melepaskan komponen yang dibuat.
Bisakah antarmuka saya mengimplementasikan IDisposable agar sesuai dengan manajemen siklus hidup? Sebaliknya, antarmuka suatu komponen tidak boleh mengimplementasikan antarmuka IDisposable yang murni merupakan masalah infrastruktur. Hanya implementasi yang mungkin terjadi. Kontainer memastikan untuk membuang implementasinya dengan benar saat mengimplementasikan antarmuka IDisposable.
Mengapa menggunakan ekspresi lambda untuk mengonfigurasi komponen alih-alih parameter generik klasik? Ekspresi Lambda menawarkan cara untuk menargetkan konstruktor yang akan digunakan, menentukan kapan menggunakan dependensi, dan menangkap konstanta.
Bagaimana ketergantungan dikonfigurasi? Cukup gunakan Metadata<T>.Value dalam ekspresi ketika Anda perlu mendapatkan kembali ketergantungan dari wadah.
Apakah injeksi konstruktor mencegah referensi siklik antar komponen? Tidak, referensi siklik adalah sebuah fitur. Ketika sebuah instance dibuat, sebenarnya tidak demikian, instance proxy yang malas disiapkan untuk meminimalkan retensi sumber daya yang tidak terpakai dan memungkinkan referensi siklik.
Dalam pratinjau, hanya konstruktor yang digunakan untuk menyiapkan komponen, apakah terbatas pada injeksi konstruktor? Tidak, ekspresi terbuka sepenuhnya. Anda dapat memasukkan metode statis, konstruktor, anggota, dan bahkan mencampur gaya yang berbeda.
Alur Kerja:
Contoh antarmuka
[AttributeUsage(AttributeTargets.Method)]
public class Read : Attribute
{
}
[AttributeUsage(AttributeTargets.Method)]
public class Operation : Attribute
{
}
public interface IService
{
[Operation]
void SaveComment(int id, string text);
[Read]
[Operation]
string GetComment(int id);
}
Contoh implementasi
public class Service : IService
{
public void SaveComment(int id, string text)
{
}
public string GetComment(int id)
{
return null;
}
}
Misalkan kita ingin mencatat semua operasi readonly. Untuk itu, kita harus mendefinisikan Pointcut yang mewakili semua metode yang bersifat operasi readonly (tempat atribut Read dan atribut Operation ditempatkan)
public class ReadonlyOperation : Pointcut.And<Pointcut<Operation>, Pointcut<Read>>
{
}
Tentukan Saran untuk dicatat sebelum dengan Trace.WriteLine sebagai contoh saat memanggil metode
public class Log : IAdvice
{
private MethodBase m_Method;
public Log(MethodBase method)
{
this.m_Method = method;
}
public void Instance<T>(T instance)
{
}
public void Argument<T>(ref T value)
{
}
public void Begin()
{
Trace.WriteLine(this.m_Method);
}
public void Await(MethodInfo method, Task task)
{
}
public void Await<T>(MethodInfo method, Task<T> task)
{
}
public void Continue()
{
}
public void Throw(ref Exception exception)
{
}
public void Throw<T>(ref Exception exception, ref T value)
{
}
public void Return()
{
}
public void Return<T>(ref T value)
{
}
public void Dispose()
{
}
}
Tentukan Aspek yang menggunakan log Saran
public class Logging : Aspect
{
override public IEnumerable<Advisor> Manage(MethodBase method)
{
yield return Advice
.For(method)
.Around(() => new Log(method));
}
}
Buat instance Aspect dan masukkan ke ReadonlyOperation Pointcut kami
var _logging = new Logging();
_logging.Weave<ReadonlyOperation>();
Selamat, Aspek logging sekarang dimasukkan ke semua kontrak operasi hanya baca.
Berikut serangkaian contoh untuk melihat perbedaan cara membuat dan memberi nasihat.
public class Logging : Aspect
{
override public IEnumerable<Advisor> Manage(MethodBase method)
{
//Use classic interceptor to create an 'Around' advisor (place break points in interceptor methods to test interception).
yield return Advice
.For(method)
.Around(() => new Interceptor());
//Use linq expression to generate a 'Before' advisor.
yield return Advice
.For(method)
.Before(invocation =>
{
return Expression.Call
(
Metadata.Method(() => Console.WriteLine(Metadata<string>.Value)),
Expression.Constant($"Expression : { method.Name }")
);
});
//Use linq expression to generate a 'Before' advisor.
yield return Advice
.For(method)
.Before
(
Expression.Call
(
Metadata.Method(() => Console.WriteLine(Metadata<string>.Value)),
Expression.Constant($"Expression2 : { method.Name }")
)
);
//Use ILGeneration from reflection emit API to generate a 'Before' advisor.
yield return Advice
.For(method)
.Before(advice =>
{
advice.Emit(OpCodes.Ldstr, $"ILGenerator : { method.Name }");
advice.Emit(OpCodes.Call, Metadata.Method(() => Console.WriteLine(Metadata<string>.Value)));
});
//Use simple Action to generate a 'Before' advisor.
yield return Advice
.For(method)
.Before(() => Console.WriteLine($"Action : { method.Name }"));
//Use an expression to generate an 'After-Returning-Value' Advisor
yield return Advice
.For(method)
.After()
.Returning()
.Value(_Execution =>
{
return Expression.Call
(
Metadata.Method(() => Console.WriteLine(Metadata<string>.Value)),
Expression.Call
(
Metadata.Method(() => string.Concat(Metadata<string>.Value, Metadata<string>.Value)),
Expression.Constant("Returned Value : "),
Expression.Call(_Execution.Return, Metadata<object>.Method(_Object => _Object.ToString()))
)
);
});
//Validate an email parameter value.
yield return Advice
.For(method)
.Parameter<EmailAddressAttribute>()
.Validate((_Parameter, _Attribute, _Value) =>
{
if (_Value == null) { throw new ArgumentNullException(_Parameter.Name); }
try { new MailAddress(_Value.ToString()); }
catch (Exception exception) { throw new ArgumentException(_Parameter.Name, exception); }
});
}
}
Bisakah saya merangkai beberapa Aspek ke dalam Pointcut yang sama? Ya, berhati-hatilah dalam memesan tenun.
Bagaimana cara menghapus Aspek dari Pointcut? Ada metode Rilis yang ditentukan dalam Aspect untuk menghilangkan Aspect dari Pointcut .
Apakah atribut diperlukan untuk mendefinisikan Pointcut? Tidak, Pointcut dapat didefinisikan dengan mewarisi langsung dari Pointcut dan mengimplementasikan metode abstrak Match yang menggunakan MethodBase sebagai argumen tunggal dan mengembalikan boolean untuk menunjukkan apakah suatu metode berada dalam cakupan Pointcut .
Mengapa saya harus menggunakan IPuresharp? Intersepsi didasarkan pada IPuresharp. Memang IPuresharp menambahkan tindakan build untuk menulis ulang CIL untuk membuat perakitan "Ramah Arsitek" dengan memasukkan fitur transparan dan tersembunyi untuk memberikan kontrol eksekusi penuh saat runtime.
Bisakah saya mencegat konstruktor? Jika ya, bagaimana cara menerapkannya? Intersepsi konstruktor didukung dan diperlakukan seperti metode lain dengan mendeklarasikan tipe sebagai argumen pertama dan batal untuk tipe kembalian.
Apakah tipe dan metode generik didukung? Jenis dan metode generik didukung penuh oleh injeksi.
Bisakah saya mencegat metode async? Metode asinkron didukung penuh oleh injeksi dan menawarkan cara untuk mencegat setiap langkah asinkron.