Важный
Текущий Roslyn/Source Generator имеет ограничения на доступ к частным членам упомянутых проектов. Более того, доступ к закрытым членам может привести к ситуациям, когда в IDE все работает нормально, но в процессе сборки происходит сбой. Для получения более подробной информации обратитесь к проблеме Roslyn MetadataImportOptions.All не работает в генераторах исходного кода? Чтобы избежать путаницы, я заархивирую это до тех пор, пока отношения между генераторами исходного кода и частными участниками не улучшатся.
Генератор исходного кода и высокопроизводительный строго типизированный частный метод доступа на основе .NET 8 UnsafeAccessor для модульного тестирования и среды выполнения.
[GeneratePrivateProxy(typeof(TargetType))]
генерирует прокси-сервер доступа.
using PrivateProxy ;
public class Sample
{
int _field1 ;
int PrivateAdd ( int x , int y ) => x + y ;
}
[ GeneratePrivateProxy ( typeof ( Sample ) ) ]
public partial struct SampleProxy ;
// Source Generator generate this type
partial struct SampleProxy ( Sample target )
{
[ UnsafeAccessor ( UnsafeAccessorKind . Field , Name = " _field1 " ) ]
static extern ref int ___field1__ ( Sample target ) ;
[ UnsafeAccessor ( UnsafeAccessorKind . Method , Name = " PrivateAdd " ) ]
static extern int __PrivateAdd__ ( Sample target , int x , int y ) ;
public ref int _field1 => ref ___field1__ ( target ) ;
public int PrivateAdd ( int x , int y ) => __PrivateAdd__ ( target , x , y ) ;
}
public static class SamplePrivateProxyExtensions
{
public static SampleProxy AsPrivateProxy ( this Sample target )
{
return new SampleProxy ( target ) ;
}
}
// You can access like this.
var sample = new Sample ( ) ;
sample . AsPrivateProxy ( ) . _field1 = 10 ;
Сгенерированный код полностью типизирован, вы можете получить доступ к частному файлу через IntelliSense, а при изменении частного поля можно проверить ошибку компилятора.
ref
, out
, in
и ref readonly
readonly
ref
Например, это изменяемая структура и образец статического кода, возврата ссылки и конструктора.
using PrivateProxy ;
public struct MutableStructSample
{
int _counter ;
void Increment ( ) => _counter ++ ;
// static and ref sample
static ref int GetInstanceCounter ( ref MutableStructSample sample ) => ref sample . _counter ;
// constructor sample
MutalbeStructSample ( int x , int y ) { /* ... */ }
}
// use ref partial struct
[ GeneratePrivateProxy ( typeof ( MutableStructSample ) ) ]
public ref partial struct MutableStructSampleProxy ;
var sample = new MutableStructSample ( ) ;
var proxy = sample . AsPrivateProxy ( ) ;
proxy . Increment ( ) ;
proxy . Increment ( ) ;
proxy . Increment ( ) ;
// call private static method.
ref var counter = ref MutableStructSampleProxy . GetInstanceCounter ( ref sample ) ;
Console . WriteLine ( counter ) ; // 3
counter = 9999 ;
Console . WriteLine ( proxy . _counter ) ; // 9999
// call private constructor and create instance.
var sample = MutableStructSampleProxy . CreateMutableStructFromConstructor ( 111 , 222 ) ;
Эта библиотека распространяется через NuGet, минимальные требования — .NET 8 и C# 12.
PM> Установочный пакет PrivateProxy
Пакет предоставляет только анализатор, а сгенерированный код не зависит от других библиотек.
Целевой тип и член GeneratePrivateProxy
public class /* struct */ SupportTarget
{
// field
private int field ;
private readonly int readOnlyField ;
// property
private int Property { get ; set ; }
private int GetOnlyProperty { get ; }
public int GetOnlyPrivateProperty { private get ; set ; }
public int SetOnlyPrivateProperty { get ; private set ; }
private int SetOnlyProperty { set => field = value ; }
private ref int RefGetOnlyProperty => ref field ;
private ref readonly int RefReadOnlyGetOnlyProperty => ref field ;
// method
private void VoidMethod ( ) { }
private int ReturnMethod ( ) => field ;
private int ParameterMethod ( int x , int y ) => x + y ;
private void RefOutInMethod ( in int x , ref int y , out int z , ref readonly int xyz ) { z = field ; }
private ref int RefReturnMethod ( ) => ref field ;
private ref readonly int RefReadOnlyReturnMethod ( ) => ref field ;
// static
static int staticField ;
static readonly int staticReadOnlyField ;
static int StaticProperty { get ; set ; }
static int StaticGetOnlyProperty { get ; }
public static int StaticGetOnlyPrivateProperty { private get ; set ; }
public static int StaticSetOnlyPrivateProperty { get ; private set ; }
private static int StaticSetOnlyProperty { set => staticField = value ; }
private static ref int StaticRefGetOnlyProperty => ref staticField ;
private static ref readonly int StaticRefReadOnlyGetOnlyProperty => ref staticField ;
private static void StaticVoidMethod ( ) { }
static int StaticReturnMethod ( ) => staticField ;
static int StaticParameterMethod ( int x , int y ) => x + y ;
static void StaticRefOutInMethod ( in int x , ref int y , out int z , ref readonly int xyz ) { z = staticField ; }
static ref int StaticRefReturnMethod ( ) => ref staticField ;
static ref readonly int StaticRefReadOnlyReturnMethod ( ) => ref staticField ;
static ref int StaticRefReturnMethodParameter ( ) => ref staticField ;
// constructor
SupportTarget ( ) { }
SupportTarget ( int x , int y ) { }
}
Тип прокси может быть class
=> class
или struct
, struct
=> ref struct
.
using PrivateProxy ;
public class Sample ;
// class proxy type both supports class and struct(recommend is struct)
[ GeneratePrivateProxy ( typeof ( Sample ) ) ]
public partial class SampleProxy1 ;
[ GeneratePrivateProxy ( typeof ( Sample ) ) ]
public partial struct SampleProxy2 ;
public struct SamplleStruct ;
// struct only supports ref struct(when use standard struct, analyzer shows error)
[ GeneratePrivateProxy ( typeof ( SamplleStruct ) ) ]
public ref partial struct SamplleStructProxy ;
GeneratePrivateProxyAttribute имеет два конструктора, при использовании параметра PrivateProxyGenerateKinds
можно настроить генерацию типа члена.
public GeneratePrivateProxyAttribute ( Type target ) // use PrivateProxyGenerateKinds.All
public GeneratePrivateProxyAttribute ( Type target , PrivateProxyGenerateKinds generateKinds )
[ Flags ]
internal enum PrivateProxyGenerateKinds
{
All = 0 , // Field | Method | Property | Instance | Static | Constructor
Field = 1 ,
Method = 2 ,
Property = 4 ,
Instance = 8 ,
Static = 16 ,
Constructor = 32 ,
}
В настоящее время следующие функции не поддерживаются
String
)Эта библиотека лицензируется по лицензии MIT.