I'm using Automapper to copy interfaces to different implementations (for serialization, for view model, for database mapping, etc...).
My code is a lot more complex but I've isolated the problem in the following code snippet sample.
Considering the following code, do I miss something because the second assertion is failing:
[Test]
public void AutoMapperTest()
{
Mapper.CreateMap<IMyBaseInterface, MyClass>();
Mapper.CreateMap<IMyInterface, MyClass>();
IMyBaseInterface baseInstance = new MyBaseClass{ MyBaseProperty = "MyBase" };
var concrete = Mapper.Map<MyClass>(baseInstance);
concrete.MyClassProperty = "MyClass";
MyClass mapped = Mapper.Map<IMyInterface,MyClass>(concrete);
Assert.AreEqual(concrete.MyBaseProperty, mapped.MyBaseProperty);
Assert.AreEqual(concrete.MyClassProperty, mapped.MyClassProperty);
}
Expected: "MyClass"
But was: null
public class MyClass : MyBaseClass, IMyInterface
{
public string MyClassProperty { get; set; }
}
public interface IMyInterface : IMyBaseInterface
{
string MyClassProperty { get; }
}
public class MyBaseClass : IMyBaseInterface
{
public string MyBaseProperty { get; set; }
}
public interface IMyBaseInterface
{
string MyBaseProperty { get; }
}
Environment:
Automapper : 4.1.1.0 / .Net: 4.5 / VS 2013
Work around:
Add Mapper.CreateMap<MyClass, MyClass>();
I don't see the above as a real answer. Since it means that if I have several implementations, I have to create mappings for all combinations. And add another mapping if I write a new implementation, even if the whole time, they all implement the same interface.
If you are using inheritance and you want to combine this with Automapper you have to say Automapper that this class is base for these classes, and these classes are children of this class. I had the same problem and it started work only when I specified ALL my inheritance relationships
Its better to check this doc page about inheritance config
Related
I have two objects, lets call them A and B.
Each contain the following property:
[IgnoreDataMember]
public string SalesforceId { get; set; }
Then I have another two objects, lets call them UpdatedA and UpdatedB, which respectively extend A and B, and include nothing but:
[DataMember(Name = "sf__Id")]
public new string SalesforceId { get; set; }
[DataMember(Name = "sf__Created")]
public bool SalesforceCreated { get; set; }
The reason for this is so that I can use ServiceStack to convert A and B to CSV files and then use it again to convert CSV files from Salesforce back to C# Objects (If I don't ignore SalesforceId, the upload to Salesforce Bulk API 2.0 will fail).
So, the first question part of this question is do I really need to create two separate classes for UpdatedA and UpdatedB, as these classes are nearly identical and are actually both poltergeists, because I only use them in the following two methods:
private Dictionary<string, A> Update(Dictionary<string, A> aByExternalIds, RelayerContext context) {
IConfiguration config = context.Config;
string url = $"{config["SalesforceInstanceBaseUrl"]}/services/data/{config["SalesforceVersion"]}/jobs/ingest/{context.job.Id}/successfulResults";
this.restClient.Get(url, context.token)
.FromCsv<List<UploadedA>>()
.ForEach((updatedA) => {
if (aByExternalIds.TryGetValue(updatedA.ExternalId, out A oldA)) {
oldA.SalesforceId = updatedA.SalesforceId;
}
});
return aByExternalIds;
}
private Dictionary<string, B> Update(Dictionary<string, B> bBySalesforceAId, RelayerContext context) {
IConfiguration config = context.Config;
string url = $"{config["SalesforceInstanceBaseUrl"]}/services/data/{config["SalesforceVersion"]}/jobs/ingest/{context.job.Id}/successfulResults";
this.restClient.Get(url, context.token)
.FromCsv<List<UploadedB>>()
.ForEach((updatedB) => {
if (bBySalesforceAId.TryGetValue(updatedB.A__c, out B oldB)) {
oldB.SalesforceId = updatedB.SalesforceId;
}
});
return bBySalesforceAId;
}
Which leads to the second part of this question.
Both of these questions are very similar. We can see that the inputs are mapped by different properties on A and B... so I think I could do something like create an interface:
public interface Identifiable {
public string getIdentifier();
}
which would could be used to return either updatedA.ExternalId or updatedB.A__c.
But I'm not sure what the method signature would look like if I'm using generics.
Also, if I don't know how I could handle FromCsv<List<UploadedA>>() and FromCsv<List<UploadedB>>() in a generic way (maybe passing in a function?)
Anyway, to sum up, what I'd like to do is reduce those these two methods to just one, and if I can remove one or both of those Uploaded classes, so much the better.
Any ideas?
How about something like this:
public interface IBase
{
string SalesforceId { get; set; }
}
public class A : IBase
{
public string SalesforceId { get; set; }
}
public class UploadedA : A
{
public new string SalesforceId {
get => base.SalesforceId;
set => base.SalesforceId = value; }
public bool SalesforceCreated { get; set; }
}
public static void Update<T, TU>(Dictionary<string, T> oldBySalesForceId, Func<TU, string> updatedId)
where TU : T
where T : IBase
{
// Call service and read csv to produce a list of uploaded objects...
// Substituting with an empty list in the example
var list = new List<TU>();
foreach (var updated in list)
{
if (oldBySalesForceId.TryGetValue(updatedId(updated), out var old))
{
old.SalesforceId = updated.SalesforceId;
}
}
}
I have removed some details that did not seem relevant for the example. This uses generics with constraints and a interface to ensure both the updated and old value has a SalesForceId.
I changed the derived class so that it uses the same SalesforceId as the base class, you could change it to virtual/override if you prefer, but it is probably not a good idea that the base and derived class both have independent properties with the same name since it will be confusing.
It uses a delegate to describe the id/key for UpdatedA/UpdatedB. You could use an interface instead if you prefer.
I admit that a large part of my trouble with this must stem from simple lack of understanding around a few of the components involved in the solution. I'm not exactly "new to" Entity Framework, code-first, nor generic types, but the inner workings of all three are still mysterious enough to me that this is giving me fits.
I have a code-first project in which I have separated-out "model" classes from "service" classes, with generalizations in both. I am NOT using the full Repository Pattern, for a variety of reasons. For most of what I am doing, the structure I have in place is working beautifully -- I understand it and it seems quite clean.
But there is one area where I am running into problems, and that is being able to pass one of my model class types as a generic parameter to an instance of a generic service object, given a string path/name of the model class.
(Background: I need to do this because I "seed" several tables in the database with initialization values from a JSON file. This JSON file contains the names of the model entities. So, at runtime, I need to get that string value, and then feed that as the type to the generic service object that does the database operations.)
Here are the pertinent code snippets:
In BaseEntity.cs I have the top-level interface and a number of abstract classes from which the specific model entities then inherit:
namespace POST.API.Models
{
public interface IEntity
{
int Id { get; set; }
}
public abstract class BaseEntity { }
public abstract class Entity : BaseEntity, IEntity
{
public virtual int Id { get; set; }
}
public abstract class TypeEntity : Entity
{
public TypeDefinition Definition { get; set; }
}
}
In BaseService.cs I have another interface and more abstract classes from which specific model service classes inherit. There is also one concrete class, here, that is generalized for performing an insert operation:
namespace POST.API.Services
{
public interface IEntityService { }
public abstract class BaseEntityService<T> : IEntityService
where T : Models.BaseEntity
{
public T Fetch(int Id)
{
using (var Db = new PostDbContext())
{
return Db.Set<T>().Find(Id);
}
}
public void Create(T Item)
{
if (Item != null)
{
using (var Db = new PostDbContext())
{
DbSet Entity = Db.Set<T>();
Entity.Add(Item);
Db.SaveChanges();
}
}
}
public IEnumerable<T> All()
{
using (var Db = new PostDbContext())
{
return (IEnumerable<T>)Db.Set<T>().ToList();
}
}
}
public abstract class BaseTypeEntityService<T> : BaseEntityService<T>
where T : Models.TypeEntity
{ }
public abstract class BasePropertyTypeEntityService<T> : BaseTypeEntityService<T>
where T : Models.PropertyTypeEntity { }
public abstract class BasePropertyEntityService<T> : BaseEntityService<T>
where T : Models.BaseEntity { }
public class TypeEntityService<T> : BaseTypeEntityService<T>
where T : Models.TypeEntity { }
#endregion
}
I've removed some methods not pertinent to the presentation.
I have some code that then attempts to use these base classes to rummage through the JSON file and insert some rows, thus:
using (PostDbContext Db = new PostDbContext())
{
string JsonString = System.IO.File.ReadAllText(JsonDataFile);
DataSet JsonDataSet = JsonConvert.DeserializeObject<DataSet>(JsonString);
foreach (DataTable Table in JsonDataSet.Tables)
{
Type EType = Type.GetType("POST.API.Models." + Table.TableName);
POST.API.Models.BaseEntity E = (POST.API.Models.BaseEntity)Activator.CreateInstance(EType);
Services.TypeEntityService<EType> S = new Services.TypeEntityService<EType>();
foreach (DataRow Row in Table.Rows)
{
// Set properties of E and call Create method of S
}
}
}
I've clearly misunderstood something fundamental, because that code won't compile. On this line of code:
Services.TypeEntityService<EType> S = new Services.TypeEntityService<EType>();
...I get an error on my references to EType, with the compiler complaining "The type or namespace `EType' could not be found."
So, obviously, that reference, there, cannot be evaluated at runtime. Which, then, makes me wonder how on earth do I do this. All the related topics seem to yield no satisfactory answer -- at least not in a way that makes sense in the context of my own implementation.
You need to create the Services.TypeEntityService<EType> with the Activator, something like below...
Type EType = Type.GetType("POST.API.Models." + Table.TableName);
Type[] typeArgs = { EType };
var generic = typeof(Services.TypeEntityService<>).MakeGenericType(typeArgs);
var S = Activator.CreateInstance(generic);
Well you have a variabl of type System.Type in EType. You cannot use Type instances for generic types. You shouldchange your implementation of Services.TypeEntityService to take runtime Type instances (e.g TypeEntityService(System.Type type)).
Edit: Or actually like the other answer states, use Reflection to build Generic parameters from your Type instance. That makes more sense.
Consider the following class and interfaces:
public interface A { string Property { get; set; } }
public interface B { string Property { get; set; } }
public interface C : A, B { }
public class MyClass : C
{
public string Property { get; set; }
}
Looks simple, right? Now consider the following program:
static void Main(string[] args)
{
MyClass myClass = new MyClass();
myClass.Property = "Test";
A aTest = myClass;
B bTest = myClass;
C cTest = myClass;
aTest.Property = "aTest";
System.Console.WriteLine(aTest.Property);
bTest.Property = "bTest";
System.Console.WriteLine(bTest.Property);
cTest.Property = "cTest";
System.Console.WriteLine(cTest.Property);
System.Console.ReadKey();
}
Looks okay, but it will not compile. It gives me an Ambiguity exception:
Why isn't C# able to figure this out? Is what I'm doing crazy from an architectural point of view? I'm trying to understand the why (I know it can be solved with casting).
EDIT
The problems arose when I introduced interface C. When I use MyClass : A, B I've got no problems at all.
FINAL
Just finised a blog about the subject: Interface Ambiguity and Implicit Implementation.
In short because it's ambiguous indeed.
Now more detailed story. As you've already seen there is explicit interface implementation, so you can have two different implementations for A.Property and B.Property and when you have only C there is no way you can tell if implementations are the same or not. Since C# "philosophy" is not to guess what you meant, but make you state it more clear when necessary, compiler does not choose either A.Property or B.Property, but reports an error.
You need explicit interface implementation:
public interface A { string Property { get; set; } }
public interface B { string Property { get; set; } }
public interface C : A, B { }
public class MyClass : C
{
string B.Property { get; set; }
string A.Property { get; set; }
}
When it comes time to call them you are going to have to do:
MyClass c = new MyClass();
Console.WriteLine("Property A is ": ((A)c).Property);
Why don't you do:
public class MyClass : C
{
string B.Property { get; set; }
string A.Property { get; set; }
string B { get { return B.Property; } set { B.Property=value; } }
string A { get { return A.Property; } set { A.Property=value; } }
}
And it should be noted this is bad design, if you are going to expose an interface C, make sure you find a better way to expose A/B.Property.
What's to figure out? cTest is of type "C", and it inherits "Property" from two different classes; the compiler doesn't know which one you want. This sort of behavior is inherited from C++; it's the classic example of "why multiple inheritance is a Pandora's box."
Other object-oriented languages -- Java is a notable example -- avoid this problem by definition : like-named/like-signatured methods are fused in a common descendent.
When you inherit from a single interface the compiler can determine exactly which method you are interested in implementing when you add the new method.
However when multiple interfaces have the same method, the underlying (and correct) assumption is that each interface expects a DIFFERENT implementation for the method, due to the fact that those methods or properties are defined on different interfaces.
So the compiler tells you that these different interfaces require an explicit implementation for each of these properties.
The fact that two interfaces share the same NAME for a property or method is arbitrary - there is no reason to assume that they share anything OTHER then the name, so the compiler protects you from making the mistake of implicitly treating them in the same way.
It is not simple, and it doesn't look simple either. In case of a name collision between two interfaces, .NET needs to ask you which interface are you trying to implement. Its way to ask you this is via the ambiguity error.
If you didn't have this kind of errors, you would end up implementing interfaces by chance.
you need to explicity implement both properties from each interface:
public class MyClass : C
{
string A.Property { get; set; }
string B.Property { get; set; }
}
Because what you are doing is not right. A and B are clashing and have the same name for the property... you need to use Explicit implementation of interface.
Reference here.
There are a lot of answers, and all of them are right, as explicit interface implementation is the answer to your problem.
I'll try to clarify the motivation behind this design with a somewhat convoluted example:
Let's say I have an interface for people that run (with possible implementations like LongDistanceRunner, Jogger, MarathonMan, etc)
public interface IRunner
{
void Run();
}
and an interface for devices that can be turned on and ran (with possible implementations BathTub, Application, Dishwasher, etc)
public interface IRunnable
{
void Run();
}
Now I want to create and interface for a IMusicallJogger (implementations like JoggerWithIpod,BoomBoxJogger, etc)
public interface IMusicalJogger : IRunner, IRunnable {}
public class BoomBoxJogger : IMusicalJogger
{
// code here
}
BoomBoxJogger bbJogger = new BoomBoxJogger();
Now, when I say bbJogger.Run() what should my object do? Should it start running across the park, or should it turn on the boombox, or both, or something else entirely? If I implement both the class and the callsite, it might be obvious that I want my joggers to do both, but what if I control just the callsite? And what if there are other implementations of the interface that do something else? And what if my jogger starts running across the park, when it's used in a context where it is considered like a device (through casting).
That's where explicit interface implementation comes into play.
I have to define my class like this:
public class BoomBoxJogger : IMusicalJogger
{
void IRunner.Run() //implementation of the runner aspect
{
Console.WriteLine("Running through the park");
}
void IRunnable.Run() //implementation of the runnable aspect
{
Console.WriteLine("Blasting out Megadeth on my boombox");
}
public void Run() //a new method defined in the class itself
{
Console.WriteLine("Running while listening to music");
}
}
and then, when I call, I have to specify what aspect of my jogger I want to use:
BoomBoxJogger bbJogger = new BoomBoxJogger();
((IRunner).bbJogger).Run(); // start running
((IRunnable).bbJogger).Run(); // blast the boombox
//and of course you can now do
bbJogger.Run //running while listening
((IMusicalJogger)jogger).Run(); //compiler error here, as there is no way to resolve this.
Hope I helped clarify the concept.
I have an interesting issue today!! Basically I have two classes.
public class A : B
{
public virtual new ISet<DifferentItem> Items {get;set;}
}
public class B
{
public virtual int Id {get;set;}
public virtual ISet<Item> Items {get;set;}
}
The subclass A hides the base class B property, Items and replaces it with a new property with the same name and a different type.
The mappings for these classes are
public class AMapping : SubclassMap<A>
{
public AMapping()
{
HasMany(x=>x.Items)
.LazyLoad()
.AsSet();
}
}
public class BMapping : ClassMap<B>
{
public BMapping()
{
Id(x=>x.Id);
HasMany(x=>x.Items)
.LazyLoad()
.AsSet();
}
}
However when I run my unit test to check the mapping I get the following exception:
Tests the A mapping: NHibernate.PropertyAccessException : Invalid Cast (check your mapping for property type mismatches); setter of A
----> System.InvalidCastException : Unable to cast object of type 'NHibernate.Collection.Generic.PersistentGenericSet1[Item]' to type 'Iesi.Collections.Generic.ISet1[DifferentItem]'.
Anyone have any ideas?
Clearly it is something to do with the type of the collection on the sub-class. But I skimmed through the available options on the mapping class and nothing stood out as being the solution here.
Generics in c# does not support covariance, so essentially you can't have ISet<Item> and ISet<DifferentItem>. Since it's a limitation of the language you need to rethink your design. Or wait til c# 6.
This code compiles but looks very strange.
I have a typical and simple parent/child relationship here which is implemented using generics in a very strange way.
But I can't seem to find any other way of doing it.
class SampleObject<T> //I don't want to make this a generic but am forced to
{
//The SampleContainer this object is in
//This must be located in this base class
public SampleContainer<T> Parent { get; set; }
}
class SpecificObject : SampleObject<SpecificObject>
//SampleObject<SpecificObject> !!? This is the bizzare bit
//It seems really strange but necessary for compilation to work
{
}
//A class to contain a List of objects derived from SampleObjects
class SampleContainer<T>
{
public List<T> List;
}
class Start
{
public void Test()
{
SampleContainer<SpecificObject> container = new SampleContainer<SpecificObject>();
SpecificObject o = new SpecificObject(); //create an object
container.List.Add(o); //add it to the list
o.Parent = container; //set its parent
}
}
Can this code be simplified?
This seems to work without the type.
Is this what you were looking for?
class SampleObject //I don't want to make this a generic but am forced to
{
//The SampleContainer this object is in
//This must be located in this base class
public SampleContainer<SampleObject> Parent;//{ get; set; }
}
class SpecificObject : SampleObject
//SampleObject<SpecificObject> !!? This is the bizzare bit
//It seems really strange but necessary for compilation to work
{
}
//A class to contain a List of objects derived from SampleObjects
class SampleContainer<T>
{
public List<T> List;
}
class Start
{
public void Test()
{
SampleContainer<SampleObject> container = new SampleContainer<SampleObject>();
SpecificObject o = new SpecificObject(); //create an object
container.List.Add(o); //add it to the list
o.Parent = container; //set its parent
}
}
In the MSDN documentation, it states that:
When deriving from a generic base
class, you must provide a type
argument instead of the base-class's
generic type parameter:
public class BaseClass<T>
{...}
public class SubClass : BaseClass<int>
{...}
It's probably a constraint that the C# designers set up in the compiler. They require that a derived type must specify the type of the generic argument at compile time. I'm not quite sure why.
Generics can create some unwieldy class hierarchies. However, the syntax for SpecificObject : SampleObject does make sense, since you're stating that the object has a parent relationship. The only other way I could see you do this, would be to split out the hierarchy with an interface. It doesn't buy much, but it may help clarify the intent.
interface IHasParent<T>
{
T Parent { get; set; }
}
public class SpecificObject : IHasParent<SpecificObject>
{
public SpecificObject Parent { get; set; }
}
If you're concerned about how verbose your collection is, you can tame the angle brackets a bit by using:
public SpecificObjectContainer : Container<SpecificObject>
{
}