Note: this question is now out of date and only applies to old versions of AutoMapper. The bug referred to here has been fixed.
Problem:
I have an AutoMapper converter that takes a Nullable<bool>/bool? and returns a string. I apply this globally to my profile, and it works for true and false but not for null.
Here is what I have in my AutoMapper profile:
CreateMap<bool?, string>()
.ConvertUsing<NullableBoolToLabel>();
And here is the converter class:
public class NullableBoolToLabel : ITypeConverter<bool?, string>
{
public string Convert(bool? source)
{
if (source.HasValue)
{
if (source.Value)
return "Yes";
else
return "No";
}
else
return "(n/a)";
}
}
Example that demonstrates problem
public class Foo
{
public bool? IsFooBarred { get; set; }
}
public class FooViewModel
{
public string IsFooBarred { get; set; }
}
public class TryIt
{
public TryIt()
{
Mapper.CreateMap<bool?, string>().ConvertUsing<NullableBoolToLabel>();
Mapper.CreateMap<Foo, FooViewModel>();
// true (succeeds)
var foo1 = new Foo { IsFooBarred = true };
var fooViewModel1 = Mapper.Map<Foo, FooViewModel>(foo1);
Debug.Print("[{0}]", fooViewModel1.IsFooBarred); // prints: [Yes]
// false (succeeds)
var foo2 = new Foo { IsFooBarred = false };
var fooViewModel2 = Mapper.Map<Foo, FooViewModel>(foo2);
Debug.Print("[{0}]", fooViewModel2.IsFooBarred); // prints: [No]
// null (fails)
var foo3 = new Foo { IsFooBarred = null };
var fooViewModel3 = Mapper.Map<Foo, FooViewModel>(foo3);
Debug.Print("[{0}]", fooViewModel3.IsFooBarred); // prints: []
// should print: [(n/a)]
}
}
Questions:
Is this a bug or by design?
If it's by design, what is the reasoning behind it working this way?
Can you recommend a workaround?
Do you need to specify a ConvertUsing for the Map? Otherwise, I'm not sure how it would know how to use the IsFooBarred member of the Foo class. But I'm not familar with the Mapper, and perhaps it can figure this out (it does seem to in the first two cases).
If you put a breakpoint in Convert does it get hit (in the debugger) in any of the 3 cases?
This was a bug in AutoMapper and has since been fixed.
The ITypeConverter interface has also changed since this question was asked. The converter would now look like this:
public class NullableBoolToLabel : ITypeConverter<bool?, string>
{
public string Convert(ResolutionContext context)
{
var source = (bool?)context.SourceValue;
if (source.HasValue)
{
if (source.Value)
return "Yes";
else
return "No";
}
else
return "(n/a)";
}
}
Related
Say we work with this class:
public class UsefulClass
{
public string A { get; set; }
public string B { get; set; }
public int? C { get; set; }
public int? D { get; set; }
public decimal E { get; set; }
public decimal F { get; set; }
}
Let's consider the following instance:
UsefulClass z_objUsefulInstance = new UsefulClass()
{
A = null,
C = null,
E = 0
};
At this point, z_objUsefulInstance.A and C are null, E is 0, B, D and F have not been initialized.
Is there a way to tell, automatically, which properties of z_objUsefulInstance haven't been initialized and which ones have been initialized with null or 0?
EDIT: by popular demand, why I need this: to emulate a system of database access akin to EntityFramework. Right now all properties are a specific generic type, so it's rather easy to know which is null and which is Generic<T>.HasNullValue == true. But that generic type causes various issues and now we'd like to get rid of it, particularly as we have grown more conversant with Expressions.
Is there a way to tell, automatically, which properties of z_objUsefulInstance haven't been initialized and which ones have been initialized with null or 0?
You can't really know in ways that you can easily inspect at runtime what properties have been set unless you intercept the property setter and set some sort of flag. from a first-principals perspective that would resemble something like this:
public class UsefulClass
{
public string A { get => _a; set { _a = value; A_Set = true; } }
private string _a;
private bool A_Set = false;
public string B { get => _b; set { _b = value; B_Set = true; } }
private string _b;
private bool B_Set = false;
public int? C { get => _c; set { _c = value; C_Set = true; } }
private string _c;
private bool C_Set = false;
public int? D { get => _d; set { _d = value; D_Set = true; } }
private string _d;
private bool D_Set = false;
public decimal E { get => _e; set { _e = value; E_Set = true; } }
private string _e;
private bool E_Set = false;
public decimal F { get => _f; set { _f = value; F_Set = true; } }
private string _f;
private bool F_Set = false;
}
It is pretty verbose, but you can see here how we are not comparing the value at all, we can determine definitively if each property has been set, thought not specifically during the initialization of the instance, this simple code only tracks if each property was set at all.
So after your init, we can inspect these new flags:
UsefulClass z_objUsefulInstance = new UsefulClass()
{
A = null,
C = null,
E = 0
};
Console.WriteLine(z.C_Set); // True
Console.WriteLine(z.D_Set); // False
We can simplify this with a dictionary for the backing store and helper methods to get and set the property values, we can even encapsulate that logic in a base class to make this easier to consume:
public class UsefulClass : PropertyTracker
{
public string A { get => GetProperty<string>(); set => SetProperty(value); }
public string B { get => GetProperty<string>(); set => SetProperty(value); }
public int? C { get => GetProperty<int?>(); set => SetProperty(value); }
public int? D { get => GetProperty<int?>(); set => SetProperty(value); }
public decimal E { get => GetProperty<decimal>(); set => SetProperty(value); }
public decimal F { get => GetProperty<decimal>(); set => SetProperty(value); }
}
public abstract class PropertyTracker
{
private Dictionary<string, object> _values = new Dictionary<string, object>();
protected void SetProperty<T>(T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
_values[propertyName] = value;
}
protected T GetProperty<T>([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)
{
if (!_values.ContainsKey(propertyName))
return default;
return (T)_values[propertyName];
}
public bool IsSet(string propertyName)
{
return _values.ContainsKey(propertyName);
}
}
See we still have the concept of a backing store, it's just not a field anymore. The inspection code is a bit different too:
UsefulClass z_objUsefulInstance = new UsefulClass()
{
A = null,
C = null,
E = 0
};
Console.WriteLine(z.IsSet(nameof(UsefulClass.C)); // True
Console.WriteLine(z.IsSet(nameof(UsefulClass.D)); // False
There are all sorts of techniques you can use to scaffold this or similar code out across your classes, this is just an example implementation. You could even write a generic wrapper that uses reflection to do the same thing. In my solutions I tend to use T4 templates to generate what are effectively View Model classes. My main argument was that I could generate some verbose code and take a hit at compile-time instead of a performance hit at runtime with a reflection based implementation.
If your ViewModel classes inherit from your model class, then you can get close to an apparently automatic implementation that is more compatible with the rest of your runtime, but that would require your properties be declared as virtual to enable the inheriting class to override the implementation.
If you end up going down this route, consider adding value to your classes by implementing INotifyPropertyChanged, or perhaps IChangeTracking or IRevertibleChangeTracking while you're there.
UsefulClass z_objUsefulInstance = new UsefulClass() {
A = null
C = null,
E = 0
};
At this point, z_objUsefulInstance.A and C are null, E is 0,
B, D and F have not been initialized.
No that's not quite right.
From "14.11.4 Constructor Execution" in the C#7 language spec
Variable initializers are transformed into assignment statements, and these assignment statements are executed before the invocation of the base class instance constructor.
So before your instance constructor in the above example is started executing, the properties are assigned
A = default(string); // null
B = default(string); // null
C = default(int?); // null
D = default(int?); // null
E = default(decimal); // 0.0m
F = default(decimal); // 0.0m
(Not quite accurate, but close enough for this answer)
Then your instance constructor is run (in this example, the default provided by the compiler), then your property assignments are made
A = null,
C = null,
E = 0
. There's no difference between E = 0 and E = default(decimal), nor is there a difference between null and null (default(string)).
If you need to tell whether a property was set or not you will have to provide a backing field, or otherwise control access to the property.
If you want to read more about constructor details, a friendlier summary than the language spec can be found at https://jonskeet.uk/csharp/constructors.html .
I actually asked a very similar question recently, but while the title mentioned classes, my content mostly referred to a tuple, and the (really great) answer reflected that. When I've tried to substitute a class in for the tuple, I get TargetParameterCountException: Parameter count mismatch. exception.
How can I get NHibernate to map to a Tuple or Class?
I have the following method to get a list of results from the database.
public static IList<T> Find<T>(DetachedCriteria crit) where T : class
{
lock (_locker)
{
return crit.GetExecutableCriteria(InstanceSession)
.List<T>();
}
}
This generally works well. However, I've changed a method that calls the method above from.
public IList<FooBarResult> FindResults(FooBarTask st)
{
return DataAccess.Find<FooBarResult>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))).ToList();
}
Which works, to this (as I don't want to return the whole of FooBarResult, just certain columns on it).
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(
Projections.Property("FieldOne") //this is a DateTime
)
.Add(
Projections.Property("FieldTwo") //this is a Guid
)
.SetResultTransformer(Transformers.AliasToBeanConstructor(typeConstructor))
)
);
}
And this is the class.
public class MyCustomClass
{
public MyCustomClass()
{
//placeholder
}
public MyCustomClass(DateTime FieldOne, Guid FieldTwo)
{
this.FieldOne = FieldOne;
this.FieldTwo = FieldTwo;
}
public DateTime FieldOne { get; set; }
public Guid FieldTwo { get; set; }
}
As mentioned earlier, when running the return crit.GetExecutableCriteria(InstanceSession).List<T>(); code I get a TargetParameterCountException: Parameter count mismatch. exception.
Is there any way I can make it return a list of my MyCustomClass?
I have not tested this, but you should use Transformers.AliasToBean take a look in to the aliases to let the transformer work:
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("FieldOne"), "FieldOne")
.Add(Projections.Property("FieldTwo"), "FieldTwo")
)
.SetResultTransformer(Transformers.AliasToBean(typeof(MyCustomClass)))
.List<MyCustomClass>()
}
In this line:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
you will get the first, default constructor and its signature obviously doesn't match. The simplest fix for your case is:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[1];
But the cleanest solution would be something along these lines (untested and also a bit simplified):
var typeConstructor = GetMatchingConstructorOrThrow<MyCustomClass>
(typeof(DateTime), typeof(Guid));
// ...
private ConstructorInfo GetMatchingConstructorOrThrow<T>(params Type[] requiredSignature)
where T : class
{
foreach (var c in typeof(T).GetConstructors())
{
var currentSignature = c.GetParameters().Select(p => p.ParameterType);
if (currentSignature.SequenceEqual(requiredSignature))
{
return c;
}
}
throw new NoMatchingConstructorFoundException();
}
Per the code below, I have a GetOrderPreviewSecurity() method that returns a Security, which is a parent class to Stock and MutualFund.
The GetOrderPreviewSecurity() method only actually returns a Stock type or MutualFund type to a Security property. The issue I'm having is trying to access the Child-specific properties as described in the //comments below.
Is there a way I can force the cast or clean this up that is cleaner than "var newThing = (ChildClass)SecurityClass;" and using newThing?
public class Stock : Security
{
public string Ask;
public string Bid;
}
public class MutualFund : Security
{
public string AssetClass;
public string Category;
}
public Security PreviewSecurity;
public Security GetOrderPreviewSecurity(_orderTickerText){
//Do stuff
if (boolean thing)
return new Stock();
else if (boolean thing)
return new MutualFund();
else
return new Security("empty");
}
//Some stuff
private void ExecutePreviewOrder()
{
if (!string.IsNullOrEmpty(_orderTickerText) && _orderShareQuantity > 0)
{
//Returns a **Security**
PreviewSecurity = _portfolioService.GetOrderPreviewSecurity(_orderTickerText);
if (PreviewSecurity is Stock)
{
//PreviewSecurity is still a Security type.
//No Bid or Ask properties available
PreviewBid = PreviewSecurity.Bid;
PreviewAsk = PreviewSecurity.Ask;
}
else if (PreviewSecurity is MutualFund)
{
//PreviewSecurity is still a Security type.
//No AssetClass or Category propeties available
PreviewAssetClass = PreviewSecurity.AssetClass;
PreviewCategory = PreviewSecurity.Category;
}
}
}
You need to have a set of parentheses around the entire thing, like this:
if (PreviewSecurity is Stock)
{
PreviewBid = ((Stock)PreviewSecurity).Bid;
PreviewAsk = ((Stock)PreviewSecurity).Ask;
}
else if (PreviewSecurity is MutualFund)
{
PreviewAssetClass = ((MutualFund)PreviewSecurity).AssetClass;
PreviewCategory = ((MutualFund)PreviewSecurity).Category;
}
I think the issue is that the dot has higher precedence than the cast operator, so first the dot operator is applied, and then the cast operator is applied to whatever is returned by the dot operator.
I do not see any problem with casting the Security back once you have type checked it.
if (PreviewSecurity is Stock)
{
PreviewBid = (Stock)PreviewSecurity.Bid;
PreviewAsk = (Stock)PreviewSecurity.Ask;
}
else if (PreviewSecurity is MutualFund)
{
PreviewAssetClass = (MutualFund)PreviewSecurity.AssetClass;
PreviewCategory = (MutualFund)PreviewSecurity.Category;
}
Question:
Can anyone tell me why my unit test is failing with this error message?
CollectionAssert.AreEquivalent failed. The expected collection contains 1
occurrence(s) of . The actual
collection contains 0 occurrence(s).
Goal:
I'd like to check if two lists are identical. They are identical if both contain the same elements with the same property values. The order is irrelevant.
Code example:
This is the code which produces the error. list1 and list2 are identical, i.e. a copy-paste of each other.
[TestMethod]
public void TestListOfT()
{
var list1 = new List<MyPerson>()
{
new MyPerson()
{
Name = "A",
Age = 20
},
new MyPerson()
{
Name = "B",
Age = 30
}
};
var list2 = new List<MyPerson>()
{
new MyPerson()
{
Name = "A",
Age = 20
},
new MyPerson()
{
Name = "B",
Age = 30
}
};
CollectionAssert.AreEquivalent(list1.ToList(), list2.ToList());
}
public class MyPerson
{
public string Name { get; set; }
public int Age { get; set; }
}
I've also tried this line (source)
CollectionAssert.AreEquivalent(list1.ToList(), list2.ToList());
and this line (source)
CollectionAssert.AreEquivalent(list1.ToArray(), list2.ToArray());
P.S.
Related Stack Overflow questions:
I've seen both these questions, but the answers didn't help.
CollectionAssert use with generics?
Unit-testing IList with CollectionAssert
You are absolutely right. Unless you provide something like an IEqualityComparer<MyPerson> or implement MyPerson.Equals(), the two MyPerson objects will be compared with object.Equals, just like any other object. Since the objects are different, the Assert will fail.
It works if I add an IEqualityComparer<T> as described on MSDN and if I use Enumerable.SequenceEqual. Note however, that now the order of the elements is relevant.
In the unit test
//CollectionAssert.AreEquivalent(list1, list2); // Does not work
Assert.IsTrue(list1.SequenceEqual(list2, new MyPersonEqualityComparer())); // Works
IEqualityComparer
public class MyPersonEqualityComparer : IEqualityComparer<MyPerson>
{
public bool Equals(MyPerson x, MyPerson y)
{
if (object.ReferenceEquals(x, y)) return true;
if (object.ReferenceEquals(x, null) || object.ReferenceEquals(y, null)) return false;
return x.Name == y.Name && x.Age == y.Age;
}
public int GetHashCode(MyPerson obj)
{
if (object.ReferenceEquals(obj, null)) return 0;
int hashCodeName = obj.Name == null ? 0 : obj.Name.GetHashCode();
int hasCodeAge = obj.Age.GetHashCode();
return hashCodeName ^ hasCodeAge;
}
}
I was getting this same error when testing a collection persisted by nHibernate. I was able to get this to work by overriding both the Equals and GetHashCode methods. If I didn't override both I still got the same error you mentioned:
CollectionAssert.AreEquivalent failed. The expected collection contains 1 occurrence(s) of .
The actual collection contains 0 occurrence(s).
I had the following object:
public class EVProjectLedger
{
public virtual long Id { get; protected set; }
public virtual string ProjId { get; set; }
public virtual string Ledger { get; set; }
public virtual AccountRule AccountRule { get; set; }
public virtual int AccountLength { get; set; }
public virtual string AccountSubstrMethod { get; set; }
private Iesi.Collections.Generic.ISet<Contract> myContracts = new HashedSet<Contract>();
public virtual Iesi.Collections.Generic.ISet<Contract> Contracts
{
get { return myContracts; }
set { myContracts = value; }
}
public override bool Equals(object obj)
{
EVProjectLedger evProjectLedger = (EVProjectLedger)obj;
return ProjId == evProjectLedger.ProjId && Ledger == evProjectLedger.Ledger;
}
public override int GetHashCode()
{
return new { ProjId, Ledger }.GetHashCode();
}
}
Which I tested using the following:
using (ITransaction tx = session.BeginTransaction())
{
var evProject = session.Get<EVProject>("C0G");
CollectionAssert.AreEquivalent(TestData._evProjectLedgers.ToList(), evProject.EVProjectLedgers.ToList());
tx.Commit();
}
I'm using nHibernate which encourages overriding these methods anyways. The one drawback I can see is that my Equals method is based on the business key of the object and therefore tests equality using the business key and no other fields. You could override Equals however you want but beware of equality pollution mentioned in this post:
CollectionAssert.AreEquivalent failing... can't figure out why
If you would like to achieve this without having to write an equality comaparer, there is a unit testing library that you can use, called FluentAssertions,
https://fluentassertions.com/documentation/
It has many built in equality extension functions including ones for the Collections. You can install it through Nuget and its really easy to use.
Taking the example in the question above all you have to write in the end is
list1.Should().BeEquivalentTo(list2);
By default, the order matters in the two collections, however it can be changed as well.
I wrote this to test collections where the order is not important:
public static bool AreCollectionsEquivalent<T>(ICollection<T> collectionA, ICollection<T> collectionB, IEqualityComparer<T> comparer)
{
if (collectionA.Count != collectionB.Count)
return false;
foreach (var a in collectionA)
{
if (!collectionB.Any(b => comparer.Equals(a, b)))
return false;
}
return true;
}
Not as elegant as using SequenceEquals, but it works.
Of course to use it you simply do:
Assert.IsTrue(AreCollectionsEquivalent<MyType>(collectionA, collectionB, comparer));
Is it possible to modify the attribute of a property at runtime?
let's say I have some class:
public class TheClass
{
[TheAttribute]
public int TheProperty { get; set; }
}
Is there a way to do this?
if (someCondition)
{
// disable attribute. Is this possible and how can this be done?
}
No this is not possible. You cannot modify attribute values from metadata, or metadata in general, at runtime
Strictly speaking the above is not true. There are certain APIs which do allow allow for some metadata generation and modification. But they are very scenario specific, (ENC, profiling, debugging) and should not be used in general purpose programs.
It depends; from a reflection perspective: no. You can't. But if you are talking about attributes used by System.ComponentModel in things like data-binding, they you can use TypeDescriptor.AddAttributes to append extra attributes. Or other customer models involving custom descriptors. So it depends on the use-case.
In the case of xml serialization, it gets more interesting. Firstly, we can use fun object models:
using System;
using System.Xml.Serialization;
public class MyData
{
[XmlAttribute]
public int Id { get; set; }
[XmlAttribute]
public string Name { get; set; }
[XmlIgnore]
public bool NameSpecified { get; set; }
static void Main()
{
var ser = new XmlSerializer(typeof(MyData));
var obj1 = new MyData { Id = 1, Name = "Fred", NameSpecified = true };
ser.Serialize(Console.Out, obj1);
Console.WriteLine();
Console.WriteLine();
var obj2 = new MyData { Id = 2, Name = "Fred", NameSpecified = false };
ser.Serialize(Console.Out, obj2);
}
}
The bool {name}Specified {get;set;} pattern (along with bool ShouldSerialize{name}()) is recognised and used to control which elements to include.
Another alternative is to use the non-default ctor:
using System;
using System.Xml.Serialization;
public class MyData
{
[XmlAttribute]
public int Id { get; set; }
public string Name { get; set; }
static void Main()
{
var obj = new MyData { Id = 1, Name = "Fred" };
XmlAttributeOverrides config1 = new XmlAttributeOverrides();
config1.Add(typeof(MyData),"Name",
new XmlAttributes { XmlIgnore = true});
var ser1 = new XmlSerializer(typeof(MyData),config1);
ser1.Serialize(Console.Out, obj);
Console.WriteLine();
Console.WriteLine();
XmlAttributeOverrides config2 = new XmlAttributeOverrides();
config2.Add(typeof(MyData), "Name",
new XmlAttributes { XmlIgnore = false });
var ser2 = new XmlSerializer(typeof(MyData), config2);
ser2.Serialize(Console.Out, obj);
}
}
Note though that if you use this second approach you need to cache the serializer instance, as it emits an assembly every time you do this. I find the first approach simpler...
Attributes are baked into code at compilation time. The only way you can define new attributes at run time is to generate new code at runtime (using Reflection.Emit, for example). But you cannot change the attributes of existing code.
You can put Boolean variable in the class to disable/enable the property instead of disabling it at run time.
You might want to look at this http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/5b0d356d-d006-43ff-bfcd-aa90dd8de6db
And Dave Morton's explanation on this blog http://blog.codinglight.com/2008/10/changing-attribute-parameters-at.html
Sounds like you want to consider implementing IXmlSerializable
You can implement IDataErrorInfo, then check range in Validate method.
public string this[string property] {
get { return Validate(property); }
}
public string Error { get; }
protected virtual string Validate(string property) {
var propertyInfo = this.GetType().GetProperty(property);
var results = new List<ValidationResult>();
var result = Validator.TryValidateProperty(
propertyInfo.GetValue(this, null),
new ValidationContext(this, null, null) {
MemberName = property
},
results);
if (!result) {
var validationResult = results.First();
return validationResult.ErrorMessage;
}
return string.Empty;
}
In sub class
protected override string Validate(string property) {
Debug.WriteLine(property);
if (property == nameof(YourProperty)) {
if (_property > 5) {
return "_property out of range";
}
}
return base.Validate(property);
}