I have class with private readonly field
public class Bar
{
private readonly ICollection<Foo> somePrivateCollection = new HashSet<Foo>();
public IEnumerable<Foo> SomePublicCollection => somePrivateCollection;
public int z;
}
And
public class Foo
{
public int x;
}
I can set this field by GetField => SetValue
[Fact]
public void someTest()
{
var fooObjects = new Faker<Foo>().Generate(1);
var barObject = new Faker<Bar>().RuleFor(t => t.z, f => f.Random.Int())
.Generate();
barObject.GetType()
.GetField("somePrivateCollection", System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance)
.SetValue(barObject, fooObjects);
}
But how can I set this field using same style
var barObject = new Faker<Bar>().RuleFor(t => t.z, f => f.Random.Int())
.RuleSetter("somePrivateCollection",fooObjects)
.Generate();
if difference between public and private field just in 1 letter
public class PrivateBinder : Binder
{
public override Dictionary<string, MemberInfo> GetMembers(Type t)
{
var members = base.GetMembers(t);
var privateBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;
var allPrivateMembers = t.GetMembers(privateBindingFlags)
.OfType<FieldInfo>()
.Where( fi => fi.IsPrivate )
.Where( fi => !fi.GetCustomAttributes(typeof(CompilerGeneratedAttribute)).Any() )
.ToArray();
foreach( var privateField in allPrivateMembers ){
members.Add(privateField.Name, privateField);
}
return members;
}
}
public class DataFaker<T> : Faker<T> where T : class
{
public DataFaker(IBinder backingFieldBinder): base(binder: backingFieldBinder)
{
}
public DataFaker<T> UsingPrivate()
{
return base.CustomInstantiator(f => Activator.CreateInstance(typeof(T), nonPublic: true) as T)
as DataFaker<T>;
}
public virtual Faker<T> RuleForPrivate<TProperty>(Expression<Func<T, TProperty>> property, TProperty value)
{
var propName = PropertyName.For(property);
propName = propName.First()
.ToString()
.ToLower() +
propName.Substring(1);
return AddRule(propName, (f, t) => value);
}
}
var data =new DataFaker<Bar>(backingFieldBinder).UsingPrivate().RuleForPrivate(x => x.SomeCollection, value)