So, I have a object with a lot of IEnumerable properties.
In a unit test i want to do something like this:
var subsequentAgreement = _fixture.Build<Foo>()
.With(dto => dto.Bars,
_fixture.CreateMany<Bar>())
.Create();
And for the other IEnumerable<T> properties i want a Enumerable.Empty<T>()
I have a ISpecimenBuilder
public class EmptyEnumerableBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
object returnObject = new NoSpecimen(request);
var type = request as Type;
if (type != null && type.IsGenericType)
{
var typeArguments = type.GetGenericArguments();
if(!typeArguments.Any() || typeof(IEnumerable<>) == type.GetGenericTypeDefinition())
returnObject = Array.CreateInstance(typeArguments.Single(), 0);
}
return returnObject;
}
}
which i add like so: _fixture.Customizations.Add(new EmptyEnumerableBuilder());
And that works just fine, except all of the other objects i create now have Empty enumerables.
I am looking for a way to apply this EmptyEnumerableBuilder for a single _fixture.Build<>() and leave the rest default, but i can't seem to find a way.
I have tried using a type limitation like so:
_fixture.Customize<SubsequentAgreementLimitationsDto>(composer => new EmptyEnumerableBuilder());
But strangely all other objects created by fixture still have empty enumerables
If you need something convention-driven, you may be able to use Albedo to empty all writable IEnumerable<> properties. You could start with something like this:
public class EmtpyEnumerables : ReflectionVisitor<object>
{
private object value;
public EmtpyEnumerables(object value)
{
this.value = value;
}
public override object Value
{
get { return value; }
}
public override IReflectionVisitor<object> Visit(PropertyInfoElement propertyInfoElement)
{
var pi = propertyInfoElement.PropertyInfo;
if (pi.PropertyType.IsConstructedGenericType &&
pi.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>) &&
pi.CanWrite)
{
var elementType = pi.PropertyType.GetGenericArguments().Single();
pi.SetValue(value, Array.CreateInstance(elementType, 0));
return this;
}
return base.Visit(propertyInfoElement);
}
}
Assuming that Foo looks like this:
public class Foo
{
public IEnumerable<Bar> Bars { get; set; }
public IEnumerable<Baz> Bazs { get; set; }
public IEnumerable<Qux> Quxs { get; set; }
public string Corge { get; set; }
public int Grault { get; set; }
}
Then the following test passes:
[Fact]
public void FillBarsZeroOutAllOtherSequences()
{
var fixture = new Fixture();
var actual = fixture.Create<Foo>();
new TypeElement(actual.GetType()).Accept(new EmtpyEnumerables(actual));
actual.Bars = fixture.CreateMany<Bar>();
Assert.NotEmpty(actual.Bars);
Assert.Empty(actual.Bazs);
Assert.Empty(actual.Quxs);
Assert.NotEqual(default(string), actual.Corge);
Assert.NotEqual(default(int), actual.Grault);
}
If you think it's too much bother to write out new TypeElement(actual.GetType()).Accept(new EmtpyEnumerables(actual));, I'm sure you can figure out to hide it in a helper method.
Related
I'm trying to convert a collection of model objects that share a common parent, into one of DTOs. Likewise, I want to reverse the procedure - taking a collection of DTOs with a common parent into one of model objects.
From what I've read, a Factory Pattern seems to be what I'm looking for. I also have a Producer class that handles the conversion between object model and DTO by calling the relevant factory method.
There are a few limitations:
This is an open source library, and I don't want to add methods to existing classes. Otherwise a visitor pattern would have worked. Please correct me if I'm wrong.
Similarly, I don't want to add any additional packages to this project. From what I understand, AutoMapper would have been one of the ways to go about this.
I'm new(ish) to C# and design patterns, so I apologize if I am doing something that doesn't make sense.
Here is some sample code representing what I've tried so far. I used some references from online to get an idea, but something about it doesn't seem right. There was another way mentioned here: Is a switch statement applicable in a factory method? c#, but I'm not sure if that is transferrable to this scenario.
Any critique or suggestions is welcome.
Example Usage
Animal pet1 = new Pigeon("Pidgey", 100, false);
Animal pet2 = new Rattlesnake("Ekans", 20.0, true);
IList<Animal> myPets = new List<Animal>() { pet1, pet2 };
AnimalDTOProducer dtoProducer = new AnimalDTOProducer(new AnimalDTOFactory());
IList<AnimalDTO> myDTOs = new List<AnimalDTO>();
myDTOs = dtoProducer.ConvertAnimalCollection(myPets);
Models
public abstract class Animal
{
public Animal(string name)
{
Name = name;
}
public string Name { get; set; }
// business logic
}
public abstract class Bird : Animal
{
public Bird(string name, int maxAltitude, bool isReal)
: base(name)
{
Name = name;
MaxAltitude = maxAltitude;
IsReal = isReal;
}
public int MaxAltitude { get; set; }
public bool IsReal { get; set; }
// business logic
}
public class Pigeon : Bird
{
public Pigeon(string name, int maxAltitude, bool isReal)
: base(name, maxAltitude, isReal)
{
}
// business logic
}
public abstract class Snake : Animal
{
public Snake(string name, double length, bool isPoisonous)
: base(name)
{
Name = name;
Length = length;
IsPoisonous = isPoisonous;
}
public double Length { get; set; }
public bool IsPoisonous { get; set; }
// business logic
}
public class Rattlesnake : Snake
{
public Rattlesnake(string name, double length, bool isPoisonous)
: base(name, length, isPoisonous)
{
}
// business logic
}
DTOs
public abstract class AnimalDTO { }
public class PigeonDTO : AnimalDTO
{
public string Name { get; set; }
public int MaxAltitude { get; set; }
public bool IsReal { get; set; }
}
public class RattlesnakeDTO : AnimalDTO
{
public string Name { get; set; }
public double Length { get; set; }
public bool IsPoisonous { get; set; }
}
Factories
public interface IFactory { }
public interface IAnimalFactory : IFactory
{
Animal CreateAnimal(AnimalDTO DTO);
}
public interface IAnimalDTOFactory : IFactory
{
AnimalDTO CreateAnimalDTO(Animal animal);
}
public class AnimalFactory : IAnimalFactory
{
public Animal CreateAnimal(AnimalDTO DTO)
{
switch (DTO)
{
case PigeonDTO _:
var pigeonDTO = (PigeonDTO)DTO;
return new Pigeon(pigeonDTO.Name, pigeonDTO.MaxAltitude, pigeonDTO.IsReal);
case RattlesnakeDTO _:
var rattlesnakeDTO = (RattlesnakeDTO)DTO;
return new Rattlesnake(rattlesnakeDTO.Name, rattlesnakeDTO.Length, rattlesnakeDTO.IsPoisonous);
// And many more ...
default:
return null;
}
}
}
public class AnimalDTOFactory : IAnimalDTOFactory
{
public AnimalDTO CreateAnimalDTO(Animal animal)
{
switch (animal)
{
case Pigeon _:
var _pigeon = (Pigeon)animal;
return new PigeonDTO()
{
Name = _pigeon.Name,
MaxAltitude = _pigeon.MaxAltitude,
IsReal = _pigeon.IsReal
};
case Rattlesnake _:
var _rattlesnake = (Rattlesnake)animal;
return new RattlesnakeDTO()
{
Name = _rattlesnake.Name,
Length = _rattlesnake.Length,
IsPoisonous = _rattlesnake.IsPoisonous
};
// And many more ...
default:
return null;
}
}
}
Producers
public interface IProducer { }
public interface IAnimalProducer : IProducer
{
Animal ProduceAnimalFromDTO(AnimalDTO DTO);
}
public interface IAnimalDTOProducer : IProducer
{
AnimalDTO ProduceAnimalDTOFromAnimal(Animal animal);
}
public class AnimalProducer : IAnimalProducer
{
private IAnimalFactory factory;
public AnimalProducer(IAnimalFactory factory)
{
this.factory = factory;
}
public IList<Animal> ConvertAnimalDTOCollection(IList<AnimalDTO> DTOCollection)
{
IList<Animal> result = new List<Animal>();
foreach (AnimalDTO DTO in DTOCollection)
{
var dto = ProduceAnimalFromDTO(DTO);
if (dto != null)
result.Add(dto);
}
return result;
}
public Animal ProduceAnimalFromDTO(AnimalDTO animalDTO)
{
return this.factory.CreateAnimal(animalDTO);
}
}
public class AnimalDTOProducer : IAnimalDTOProducer
{
private IAnimalDTOFactory factory;
public AnimalDTOProducer(IAnimalDTOFactory factory)
{
this.factory = factory;
}
public IList<AnimalDTO> ConvertAnimalCollection(IList<Animal> collection)
{
IList<AnimalDTO> result = new List<AnimalDTO>();
foreach (Animal animal in collection)
{
var _animal = ProduceAnimalDTOFromAnimal(animal);
if (_animal != null)
result.Add(_animal);
}
return result;
}
public AnimalDTO ProduceAnimalDTOFromAnimal(Animal animal)
{
return this.factory.CreateAnimalDTO(animal);
}
}
UPDATE 1
As recommended by sjb-sjb and ChiefTwoPencils in the comments, I eliminated the switch statements from the respective factories. The result looks like this:
public class AnimalFactory : IAnimalFactory
{
public Animal CreateAnimal(AnimalDTO DTO)
{
Type srcType = DTO.GetType();
Type modelType = Type.GetType(Regex.Replace(srcType.FullName, #"(DTO)$", ""));
IList<PropertyInfo> props = new List<PropertyInfo>(srcType.GetProperties());
var propVals = props.Select(prop => prop.GetValue(DTO, null)).ToArray();
Animal animal = (Animal)Activator.CreateInstance(modelType, propVals);
return animal;
}
}
public class AnimalDTOFactory : IAnimalDTOFactory
{
public AnimalDTO CreateAnimalDTO(Animal animal)
{
Type srcType = animal.GetType();
Type dtoType = Type.GetType($"{srcType.FullName}DTO");
AnimalDTO dto = (AnimalDTO)Activator.CreateInstance(dtoType, new object[] { });
foreach (PropertyInfo dtoProperty in dtoType.GetProperties())
{
PropertyInfo srcProperty = srcType.GetProperty(dtoProperty.Name);
if (srcProperty != null)
{
dtoProperty.SetValue(dto, srcProperty.GetValue(animal));
}
}
return dto;
}
}
The one thing I forgot to mention in the original question was that the constructor for the model may have more arguments than the DTO object has properties. That, and the order of arguments may not be the same. I think in pseudo-code, a solution will look something like this:
void AssignParamsToConstructor()
{
// Extract constructer parameters with names into an ordered list
// Match DTO properties with extracted parameters via name and type
// Fill any missing parameters with a default value or null
// Pass the final list of parameters as an array to Activator.CreateInstance method
}
I will be researching on a way to resolve this for the time being, but any pointers will be welcome.
UPDATE 2
Okay, so I found a kind of hacky solution for the previous problem regarding calling the Model constructor with missing or out-of-order arguments.
I created a helper class that creates an ordered argument array based on a combination of the Model constructor arguments and the DTO properties. This array can then be passed to Activator.CreateInstance without causing any issues.
Here is the updated AnimalFactory.CreateAnimal method:
public Animal CreateAnimal(AnimalDTO DTO)
{
Type srcType = DTO.GetType();
Type modelType = Type.GetType(Regex.Replace(srcType.FullName, #"(DTO)$", ""));
object[] propVals = Helpers.GenerateConstructorArgumentValueArray(modelType, DTO);
Animal animal = (Animal)Activator.CreateInstance(modelType, propVals);
return animal;
}
And here is the helper class:
public static class Helpers
{
public static object[] GenerateConstructorArgumentValueArray(Type type, object obj)
{
IList<(string, Type)> ctorArgTypes = new List<(string, Type)>();
IList<(string, object)> propVals = new List<(string, object)>();
// Get constructor arguments
ctorArgTypes = GetConstructorArgumentsAndTypes(type);
// Get object properties
propVals = GetObjectPropertiesAndValues(obj);
// Create args array
IList<object> paramVals = new List<object>();
foreach (var ctorArg in ctorArgTypes)
{
object val;
string _name = ctorArg.Item1.ToLower();
(string, object) _namedProp = propVals.Where(prop => prop.Item1.ToLower() == _name).FirstOrDefault();
if (_namedProp.Item2 != null)
{
val = _namedProp.Item2;
}
else
{
val = ctorArg.Item2.IsValueType ? Activator.CreateInstance(ctorArg.Item2) : null;
}
paramVals.Add(val);
}
return paramVals.ToArray();
}
private static IList<(string, Type)> GetConstructorArgumentsAndTypes(Type type)
{
List<(string, Type)> ctorArgs = new List<(string, Type)>();
TypeInfo typeInfo = type.GetTypeInfo();
ConstructorInfo[] ctors = typeInfo.DeclaredConstructors.ToArray();
ParameterInfo[] ctorParams = ctors[0].GetParameters();
foreach (ParameterInfo info in ctorParams)
{
ctorArgs.Add((info.Name, info.ParameterType));
}
return ctorArgs;
}
private static IList<(string, object)> GetObjectPropertiesAndValues(object obj)
{
List<(string, object)> props = new List<(string, object)>();
PropertyInfo[] propInfo = obj.GetType().GetProperties();
foreach (PropertyInfo info in propInfo)
{
string name = info.Name;
object val = info.GetValue(obj);
props.Add((name, val));
}
return props;
}
}
I'll have to look at this later to see how it can be improved on. For the time being however, it does its job.
I would appreciate any comments or input if you have any. I will keep updating this post until I find an absolute solution.
So I worked out a solution that seems to achieve my original goal.
The reason it was difficult to solve at first was due to the original Factory class having too many responsibilities. It had to map the properties and create a new object. Separating these made it easy to implement the Generic Factory suggested by this post:
https://web.archive.org/web/20140414013728/http://tranxcoder.wordpress.com/2008/07/11/a-generic-factory-in-c
I created a simple mapper that would automatically map Entity and DTO properties. The easier solution is to use an AutoMapper like grandaCoder suggested. My situation required otherwise so a custom mapper was the way to go. I also tried to minimize calls to System.Reflection so the performance wouldn't suffer too much.
The end result is a Factory that can convert between any Entity and DTO object, maps properties between them, and can instantiate an Entity class with no default / empty constructor.
I ended up making a lot more changes to the original post, so I uploaded the end result to github: https://github.com/MoMods/EntityDTOFactory
I am open to any additional ideas / criticisms on the final solution. This is my first time solving this kind of problem, so it's very likely there are some better ideas out there.
Thanks again for the help and suggestions!
The switch statement can be avoided using reflection:
public AnimalDTO ToDTO( Animal src)
{
Type srcType = src.GetType();
Type dtoType = Type.GetType(srcType.Name + "DTO");
AnimalDTO dto = (AnimalDTO)Activator.CreateInstance(dtoType, new object[] { });
foreach (PropertyInfo dtoProperty in dtoType.GetProperties()) {
PropertyInfo srcProperty = srcType.GetProperty(dtoProperty.Name);
if (srcProperty != null) {
dtoProperty.SetValue(dto, srcProperty.GetValue(src));
}
}
return dto;
}
To get a FromDTO method, just reverse the roles of src and dto in ToDTO.
I would not reinvent the wheel on this common scenario.
https://automapper.org/
https://www.nuget.org/packages/automapper/
OR
https://github.com/MapsterMapper/Mapster
https://www.nuget.org/packages/Mapster/
.......
Learn how to use one of these frameworks.
Below is mapster..........."performance" numbers.......which is how I found it (someone told me to lookout for automapper performance)
Setup:
public class Data
{
public int A { get; set; }
public int B { get; set; }
}
public class Runner
{
public static void Run(Data data)
{
data.A = data.B;
data.A = 1;
}
}
class Program
{
static void Main(string[] args)
{
var data = new Data() { A = 1, B = 2 };
Runner.Run(data);
}
}
Problem: I need to implement change tracking here for property names not values. Inside Runner.Run on the first line data.A = data.B I need to record somehow that "A" was set to "B" (literally property names) and then on the next line data.A = 1 I need to record that "A" was set to constant and say forget about it.
Constrains:
When setting one property to another (e.g. A = B) that needs to be recorded
When setting property to anything else (e.g. A = 1 or A = B * 2) this change needs to be forgotten (e.g. remember A only)
Suppose this is the tracker contract being used:
void RecordChange(string setterName, string getterName);
void UnTrackChange(string setterName);
Question:
I would like to somehow proxy the Data class so it still can be used in the interface code (e.g. Runner - is a whole bunch of a business logic code that uses Data) INCLUDING strong-typing and it can track it's changes without modifying the code (e.g. there is lots of places like 'data.A = data.B').
Is there any way to do it without resorting to I guess some magic involving IL generation?
Already investigated/tried:
PostSharp interceptors/Castle.DynamicProxy with interceptors - these alone cannot help. The most I can get out of it is to have a value of data.B inside setter interceptor but not nameof(data.B).
Compiler services - haven't found anything suitable here - getting the name of caller doesn't really help.
Runtine code generation - smth like proxy inherited from DynamicObject or using Relfection.Emit (TypeBuilder probably) - I lose typings.
Current solution:
Use the Tracker implementation of the abovementioned contract and pass it around into every function down the road. Then instead of writing data.A = data.B use method tracker.SetFrom(x => x.A, x => x.B) - tracker holds a Data instance and so this works. BUT in a real codebase it is easy to miss something and it just makes it way less readable.
It is the closest the solution I've come up with. It isn't perfect as I still need to modify all the contracts/methods in the client code to use a new data model but at least all the logic stays the same.
So I'm open for other answers.
Here's the renewed Data model:
public readonly struct NamedProperty<TValue>
{
public NamedProperty(string name, TValue value)
{
Name = name;
Value = value;
}
public string Name { get; }
public TValue Value { get; }
public static implicit operator TValue (NamedProperty<TValue> obj)
=> obj.Value;
public static implicit operator NamedProperty<TValue>(TValue value)
=> new NamedProperty<TValue>(null, value);
}
public interface ISelfTracker<T>
where T : class, ISelfTracker<T>
{
Tracker<T> Tracker { get; set; }
}
public class NamedData : ISelfTracker<NamedData>
{
public virtual NamedProperty<int> A { get; set; }
public virtual NamedProperty<int> B { get; set; }
public Tracker<NamedData> Tracker { get; set; }
}
Basically I've copy-pasted the original Data model but changed all its properties to be aware of their names.
Then the tracker itself:
public class Tracker<T>
where T : class, ISelfTracker<T>
{
public T Instance { get; }
public T Proxy { get; }
public Tracker(T instance)
{
Instance = instance;
Proxy = new ProxyGenerator().CreateClassProxyWithTarget<T>(Instance, new TrackingNamedProxyInterceptor<T>(this));
Proxy.Tracker = this;
}
public void RecordChange(string setterName, string getterName)
{
}
public void UnTrackChange(string setterName)
{
}
}
The interceptor for Castle.DynamicProxy:
public class TrackingNamedProxyInterceptor<T> : IInterceptor
where T : class, ISelfTracker<T>
{
private const string SetterPrefix = "set_";
private const string GetterPrefix = "get_";
private readonly Tracker<T> _tracker;
public TrackingNamedProxyInterceptor(Tracker<T> proxy)
{
_tracker = proxy;
}
public void Intercept(IInvocation invocation)
{
if (IsSetMethod(invocation.Method))
{
string propertyName = GetPropertyName(invocation.Method);
dynamic value = invocation.Arguments[0];
var propertyType = value.GetType();
if (IsOfGenericType(propertyType, typeof(NamedProperty<>)))
{
if (value.Name == null)
{
_tracker.UnTrackChange(propertyName);
}
else
{
_tracker.RecordChange(propertyName, value.Name);
}
var args = new[] { propertyName, value.Value };
invocation.Arguments[0] = Activator.CreateInstance(propertyType, args);
}
}
invocation.Proceed();
}
private string GetPropertyName(MethodInfo method)
=> method.Name.Replace(SetterPrefix, string.Empty).Replace(GetterPrefix, string.Empty);
private bool IsSetMethod(MethodInfo method)
=> method.IsSpecialName && method.Name.StartsWith(SetterPrefix);
private bool IsOfGenericType(Type type, Type openGenericType)
=> type.IsGenericType && type.GetGenericTypeDefinition() == openGenericType;
}
And the modified entry point:
static void Main(string[] args)
{
var data = new Data() { A = 1, B = 2 };
NamedData namedData = Map(data);
var proxy = new Tracker<NamedData>(namedData).Proxy;
Runner.Run(proxy);
Console.ReadLine();
}
The Map() function actually maps Data to NamedData filling in property names.
I have a series of generic response objects that are being returned with a property that is an abstract class. The NSwag and NJsonSchema generate the schema with an abstract class, which creates problems. The concrete class is easily determined via reflection, however, there does not seem to be a clean way to get NJsonSchema to replace the abstract type with the appropriate concrete one. What is the correct way to do this?
public abstract class AppRequest<TData> {
public Guid RequestId { get; set; }
}
public class AppResponse<TData> {
public TData Data { get; set; }
public AppRequest<TData> OriginalRequest { get; set; }
}
public class User {
....
}
public class UserRequest: AppRequest<User> {
public Guid UserId { get; set; }
}
NSwag generates response object as AppResponseOfUser which is fine, however, it says that the OriginalRequest property is AppRequestOfUser and that it is abstract. I want to create a SchemaProcessor that remaps this AppRequestOfUser to UserRequest. Something like this:
public class MySchemaProcessor
: ISchemaProcessor
{
public async Task ProcessAsync(SchemaProcessorContext context)
{
if (context.Type.IsGenericOf(typeof(AppResponse<>)))
{
var modelType = context.Type.GenericTypeArguments[0];
var abstractRequestType = typeof(AppRequest<>).MakeGenericType(modelType);
var actualRequestType = modelType.Assembly.GetTypes()
.Single(t => t.IsClass && t.BaseType == abstractRequestType);
var requestSchema = await JsonSchema4.FromTypeAsync(actualRequestType);
var originalRequestProperty = context.Schema.Properties["originalRequest"];
originalRequestProperty.IsReadOnly = true;
originalRequestProperty.IsAbstract = false;
// CHANGE PROPERTY TYPE HERE!!!
}
}
}
Unfortunately, NJsonSchema doesn't seem to be very flexible and there is no clear way on how to do this. I do not want to use a discriminator property. I want to remap to the appropriate concrete type.
In case anyone was wondering, here is the final solution:
var classesToMap = typeof(Startup)
.Assembly
.GetTypes()
.Where(t => t.IsClass && t.BaseType.IsGenericOf(typeof(AppRequest<>)));
var settings = new JsonSchemaGeneratorSettings()
{
FlattenInheritanceHierarchy = true,
};
foreach (var type in classesToMap)
{
var actualSchema = JsonSchema4.FromTypeAsync(type,settings).Result;
options.TypeMappers.Add(new ObjectTypeMapper(type.BaseType, actualSchema));
}
I am mapping MongoDB documents to C# objects (see this question for some background) and everything works fine, however I'm starting to find some entries that are null. The reason being the XML previously just had <VehicleEntry></VehicleEntry> tags so it was inserted as 'null' into the array in the BsonDocument.
I can understand that this would be expected behavior, but when I map it to my VehicleEntry class that I wrote, it shows up as a null object. In my mapped class I have listed a bunch of BsonDefaultValues and even added a default constructor, but it still appears that if the value is 'null' in the database it will create a 'null' reference object.
How can I set this up to match a null reference to an object with all default values?
If you create your own BsonSerializers and assign it to the VehicleEntry type you'll then be able to say if the value is null then return a default(VehicleEntry)
[TestFixture]
public class StackQuestionTest
{
[Test]
public void GivenABsonDocumentWithANullForAnPossibleEmbeddedDocument_When_ThenAnInstanceIsSetAsTheEmbeddedDocument()
{
BsonSerializer.RegisterSerializationProvider(new VehicleEntryBsonSerializationProvider());
var document = new BsonDocument()
{
{"OtherProperty1", BsonString.Create("12345")},
{"OtherProperty2", BsonString.Create("67890")},
{"VehicleEntry", BsonNull.Value},
};
var rootObject = BsonSerializer.Deserialize<RootObject>(document);
Assert.That(rootObject.OtherProperty1, Is.EqualTo("12345"));
Assert.That(rootObject.OtherProperty2, Is.EqualTo("67890"));
Assert.That(rootObject.VehicleEntry, Is.Not.Null);
Assert.That(rootObject.VehicleEntry.What, Is.EqualTo("Magic"));
}
}
public class VehicleEntrySerializer : BsonClassMapSerializer<VehicleEntry>
{
public override VehicleEntry Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
if (context.Reader.GetCurrentBsonType() == BsonType.Null)
{
context.Reader.ReadNull();
return new VehicleEntry();
}
return base.Deserialize(context, args);
}
public VehicleEntrySerializer(BsonClassMap classMap) : base(classMap)
{
}
}
public class VehicleEntryBsonSerializationProvider : IBsonSerializationProvider
{
public IBsonSerializer GetSerializer(Type type)
{
if (type == typeof(VehicleEntry))
{
BsonClassMap bsonClassMap = BsonClassMap.LookupClassMap(type);
return new VehicleEntrySerializer(bsonClassMap);
}
return null;
}
}
public class RootObject
{
public string OtherProperty1 { get; set; }
public string OtherProperty2 { get; set; }
public VehicleEntry VehicleEntry { get; set; }
}
public class VehicleEntry
{
public string What { get; set; } = "Magic";
}
See http://mongodb.github.io/mongo-csharp-driver/2.0/reference/bson/serialization/
One solution is to change your LINQ to only return values that aren't null in the list:
var results = collection.AsQueryable()
.Where(v => v.ProjectName.Equals("input")
.SelectMan(v => v.VehicleEntries)
.Where(i => i != null)
.ToList();
This does not solve the problem of having the null value there, but it presents it from being returned in any results and avoids NPEs when displaying the data.
I'm not sure if I'm using Moq the right way, so if anyone could help, I'd be grateful.
I want to test the call of Clone() method on object in a collection. The test looks like this:
[Test]
public void CloneTest()
{
var mdFake = new Mock<MachineDecision>();
var clonable = mdFake.As<ICloneable>();
clonable.Setup(x => x.Clone()).Verifiable();
var decision = new Decision()
{
MachineDecisions = new List<MachineDecision> { mdFake.Object }
};
var newDecision = (Decision) decision.Clone();
clonable.Verify(x => x.Clone());
}
The test fails: Moq.MockException :
Expected invocation on the mock at least once, but was never performed: x => x.Clone() but I believe it should actually pass.
Used classes look as follows:
public class Decision : Entity<Guid>, ICloneable
{
public Decision()
{
Id = Guid.NewGuid();
MachineDecisions = new List<MachineDecision>();
}
public List<MachineDecision> MachineDecisions { get; set; }
public object Clone()
{
var obj = new Decision();
if (this.MachineDecisions != null)
{
obj.MachineDecisions = MachineDecisions.Select(item => (MachineDecision) item.Clone()).ToList();
}
return obj;
}
}
public class MachineDecision : Entity<Guid>, ICloneable
{
//...
}
There are two options available.
First, you can make an implementation of method Clone() virtual and your test will be 'Green'
public class MachineDecision : Entity<Guid>, ICloneable
{
public virtual object Clone()
{
throw new NotImplementedException();
}
}
Second, you can invoke Clone() method from ICloneable interface: (MachineDecision)(item as ICloneable).Clone(); and your test will be 'Green' also.
public class Decision : Entity<Guid>, ICloneable
{
public Decision()
{
Id = Guid.NewGuid();
MachineDecisions = new List<MachineDecision>();
}
public List<MachineDecision> MachineDecisions { get; set; }
public object Clone()
{
var obj = new Decision();
if (this.MachineDecisions != null)
{
obj.MachineDecisions = MachineDecisions.Select(item =>
{
return (MachineDecision)(item as ICloneable).Clone();
}).ToList();
}
return obj;
}
}
I realise that now it is not the best code but it is up to you how to refactor it further.
I'd do it like this:
[Test]
public void CloneTest()
{
// create the mock
var mdFake = new Mock<MachineDecision>();
var decision = new Decision
{
// setup (pass it to my collection)
MachineDecisions = new List<MachineDecision> { mdFake.Object }
};
// call the method being tested (you need to make Clone() virtual)
decision.Clone();
// check for the side effects -> It was called once !
mdFake.Verify(x => x.Clone(), Times.Once());
}
I hope this helps you.
EDIT - I'm sorry, as it was pointed in the comments - I forgot to mention, that what I'm suggesting requires you to make Clone() (in MachineDecision) - virtual, which might not be ideal in your case.
Try this:
...
clonable.Expect(x => x.Clone()).Verifiable().Returns(null);
...
clonable.Verify();