I have a couple of objects that have a corresponding object with identical properties.
class Source1
{
int id;
string name;
DateTime date;
}
class Destination1
{
int id;
string name;
DateTime date;
}
class Source2
{
int id;
string code;
double price;
}
class Destination2
{
int id;
string code;
double price;
}
Now I want to make a method with generic types that can cast an object into his corresponding object.
public TDestination Cast<TSource, TDestination>(TSource source)
{
//TDestination destination = (TDestination) source;
return destination;
}
Your best option here is to introduce a common interface (or base class). There is no other way to cast an item into another.
public interface IItem
{
int id {get;set;}
string name {get;set;}
DateTime date {get;set;}
}
class Source1 : IItem
{
public int id {get;set;}
public string name {get;set;}
public DateTime date {get;set;}
}
class Destination1 : IItem
{
public int id {get;set;}
public string name {get;set;}
public DateTime date {get;set;}
}
You can then just cast the object into the interface and access the properties.
var item1 = (IItem)sourceItem;
var item2 = (IItem)destinationItem;
If you don't want to do that another option would be to using reflection go trough the properties in the source and create a new object of the destination type and try to map properties with shared names. This would however create a new object and is not the same at all as casting. There are libraries such as AutoMapper that can help you with this.
AutoMapper.Mapper.CreateMap<Source1, Destination1>();
var destItem = AutoMapper.Mapper.Map<Destination1 >(sourceItem);
As Magnus points out, if you want to actually cast, interfaces are your way to go. However, I'm thinking you might be actually looking at converting rather then casting.
I would consider checking Automapper as it exists for exactly that.
From the documentation:
var source = new Source<int> { Value = 10 };
var dest = mapper.Map<Source<int>, Destination<int>>(source);
dest.Value.ShouldEqual(10);
You can configure mappings between two types by either naming conventions (even custom naming conventions), custom mappers or a combination of both. The most common use case I have seen for this is mapping a datatransfer object to a model and back again.
If one object is basically the other object with some extra logic and properties the Decorator pattern might be what you are looking for. Here you basically wrap (decorate) one object with some extra stuff and the decorating object links everything through to the original object.
Boris Calens pointed out Automapper, which is great, but if you want to avoid using outside code, a home-made solution for your example problem is pretty simple:
using System.Reflection;
...
TDestination Copy<TSource, TDestination>(TSource source)
where TDestination : new()
{
TDestination dest = new TDestination();
foreach (FieldInfo srcField in typeof(TSource).GetFields())
{
foreach (FieldInfo destField in typeof(TDestination).GetFields())
{
if (destField.Name == srcField.Name && destField.FieldType == srcField.FieldType)
{
destField.SetValue(dest, srcField.GetValue(source));
}
}
}
return dest;
}
You could also easily loop through the properties of the respective types; specify binding flags to filter which fields/properties get copied; and expand the comparison for determining whether the two members are of the same type (i.e. checking whether one type is derived from another).
My answer to this question (which you may also find helpful) shows a similar example, comparing properties and fields.
Related
I am working on a WCF service and I have run into a bit of a snag mapping my entities to my DTO. Consider the following
namespace Foo.Entities
{
public class Order : IOrder
{
public string Name { get;set; }
public string Address { get;set; }
public IList<ILocation> Locations { get;set; }
}
}
namespace Foo.DTO
{
[DataContract]
public class Order
{
[DataMember]
public string Name { get;set; }
[DataMember]
public string Address { get;set; }
[DataMember]
public List<Location> Locations { get;set; }
}
}
This is all very straightforward: DTO.Order is what I am returning from my endpoint and Entities.Order is what I am using internally (I am using DI / IOC) for business logic, data operations, etc. Since my business layer returns types from the Entities namespace, but the endpoint returns types from the DTO namespace I wrote a small mapping method that will take one type and map it to another type like so:
public TTarget MapObject<TSource, TTarget>(TSource source, TTarget target)
where TSource : class
where TTarget : class
{
foreach (var prop in source.GetType().GetProperties())
{
var targetProp = target.GetType().GetProperty(prop.Name, BindingFlags.Public | BindingFlags.Instance);
if(targetProp == null || !targetProp.CanWrite) continue;
if (prop.PropertyType.GetGenericTypeDefinition() == typeof (IList<>))
{
??
}
else{ targetProp.SetValue(target, prop.GetValue(source)); }
}
return target;
}
I then call this method like so:
factory.MapObject(Entities.DealerOrder, new GTO.DealerOrder())
where Entities.DealerOrder represents an instantiated object that contains data.
Everything works fine until I get to the property of type IList and I am at a loss at how to convert the IList to List. I know what needs to happen but all of the documentation I have read thus far hasn't pointed me in the right direction.
The pseudo is
if (prop.PropertyType.GetGenericTypeDefinition() == typeof (IList<>))
{
var lst = new List<type of targetProp>()
foreach(var val in prop.GetValue())
{
var item = new Location() (I have to figure out this initialization based on the List type of targetProp. In this case it would be List<Location>)
var retval = MapObject(val, item);
lst.Add(retval);
}
targetProp.SetValue(target, lst);
}
I am not sure if what I want to do is even possible. I know that Generics and Reflection don't mix well so if there is a solution it might be overly complex for what I am really trying to accomplish. If worse comes to worse I can put a static method on each of my DTO's that will accept the source type as a parameter and return an instance of the DTO, but I want to avoid having to manually map the fields from the Entity to the DTO if at all possible.
Any help is greatly appreciated.
You can use targetProp.GetGenericArguments()[0]; to get the type of item you want to map your collection content to.
You can use Activator.CreateInstance to create List<T> with T known at runtime at not at compile time.
You can use Activator.CreateInstance to create instance of the type you want to map to.
You can't rely on type inference when calling MapObject anymore. You need to create proper generic method via reflection here too, and call it.
You can't simply call Add on the list, because you don't know what kind of list it is. You can cast it to ICollection and call Add on it instead.
Can't you just use something like AutoMapper? Those are problems people already solved, why don't you use their work?
I've got two objects which (Domain and Data) which in this case have the same property (let's presume Name). I've got an Action<DomItem> which I would like to cast to Action<DataItem>.
public class DomItem {
public string Name { get; set; }
}
public class DataItem {
public string Name { get; set; }
}
public class Program {
public Program() {
Action<DomItem> domAction = new Action<DomItem>(x=>x.Name = "Test");
// Something Casted To Action<DataItem>(x=>x.Name = "Test");
}
}
Of course this is just a basic example. It's by design that I can NOT use a common interface. I do not care about the DataItem might not be having the same property.
I've been looking into Expressions and several other solutions but I just can't figure out how to create the Cast (or get the "x=>x.Name =..." part from the method).
Any help would be really appreciated!
You can't directly or indirectly cast a Action<DomItem> to an Action<DataItem>, but you could wrap the action with a converter that converts the input from a DataItem to a DomItem and runs the original action on the copy:
public Action<DataItem> Convert(Action<DomItem> action)
{
return new Action<DataItem>(o => action(Map(o)));
}
public DomItem Map(DataItem dataItem)
{
return new DomItem{Name = dataItem.Name};
}
The obvious downside is that the action will be applied to a copy of the original object and not the original object itself. Without knowing exactly what the action is I don't know of a way to "cast" the action without a common base type.
I have two custom types Customer and Employee which implement the interface ITablefy. This interface has only one method, GetPropertyList which returns a list of strings of the property names of the object that implements it. I have a web service which looks like:
public string ReturnPropertyNames(ITablefy i)
{
List<string> propList = new List<string>();
TableFactory factory = new TableFactory();
ITablefy table = factory.CreateTable(i);
propList = table.GetPropertyList(table);
return propList[1];
}
so in this example the Factory creates a concrete type that implements ITablefy
I realized when I had a problem when both of my classes Customer and Employee implemented their GetPropertyList methods exactly the same:
//property list is a private member variable in each class
public List<string> GetPropertyList(ITablefy i)
{
TableFactory factory = new TableFactory();
ITablefy table = factory.CreateTable(i);
foreach (var propInfo in table.GetType().GetProperties())
{
propertyList.Add(propInfo.Name);
}
return propertyList;
}
Rather than copy and paste that code I'm looking for a better solution to what I have currently. If I only want certain types to use the GetPropertyList method how can I control that without having to copy and paste this same code? Harcoding the type to create in each class doesn't seem like a good solution to me. Employee and Customer don't logically make sense to use inheritance either. What's a proper solution for something like this?
factory:
public class TableFactory
{
public ITablefy CreateTable(ITablefy i)
{
if (i is Employee)
{
return new Employee();
}
else if (i is Customer)
{
return new Customer();
}
else
{
return null;
}
}
}
public static List<string> GetPropertyNames(this Object o)
{
List<string> names = new List<string>
foreach (PropertyInfo prop in o.GetType().GetProperties())
names.Add(prop.Name);
return names;
}
Now you can implement ITablefy in terms of any object.GetPropertyNames() using the extension method above.
There are a few questions that comes to my mind:
If It's so easy to do generically, why are you even using the interface?
Shouldn't you be checking properties for public accessors?
Shouldn't your interface be returning a more general type like IEnumerable<string> or ICollection<string>?
Wouldn't the interface be better designed to filter out property names that you don't want? That way you could assume all public properties are part of the set except those that aren't.
You make the interface be something like:
public interface IPropertyInfoFilterProvider {
public Func<PropertyInfo, bool> PropertyInfoSkipFilter { get; set; }
}
or
public interface IPropertyNameFilterProvider {
public Func<string, bool> PropertyNameSkipFilter { get; set; }
}
and then you can initialize the default to (prop) => false.
so now you can harvest the property names automagically and in one place and let implementations determine what gets taken and what doesn't and your harvesting code could use that filter in a linq where clause.
You could make it an extension method on ITablefy.
Or a static method on ITablefy
I have two lists of different objects, one from a third party API and one from my database - and I'm trying to link the two as a relationship. Ideally with a similar effect of how DBML's create relationships for tables with foreign keys (Customer.Orders).
From third party:
class ApiObject {
public string ID { get; set; }
public string Title { get; set; }
public DateTime CreatedDate { get; set; }
... 30 other properties ...
}
From my database:
class DbmlObject {
public int ID { get; set; }
public string ApiID { get; set; }
public string OtherString { get; set; }
}
They are related through ApiObject.ID == DbmlObject.ApiID
I do not want to merge these, nor join them into some anonymous object (and explicitly list 30+ properties) - but rather to make the DbmlObject a linked property of ApiObject. i.e.: addressable as:
apiObject.DbmlObjects.First().OtherString or ideally apiObject.DbmlObject.OtherString since it is a 1 to 1 relationship.
In controller:
List<ApiObject> apiObjects = _thirdParty.GetObjects();
DbmlDataContext model = new DbmlDataContext();
List<DbmlObject> dbmlObjects = model.GetAllDbmlObjects();
// relate them here
foreach (var apiObject in apiObjects)
Console.Write(apiObject.DbmlObject.OtherString)
// NOTE: ideally this foreach loop should not make a DBML query on each iteration, just the single GetAllDbmlObjects query above.
It sounds like a join:
var combined = from api in apiObjects
join dbml in dbmlObjects on api.ID equals dbml.ApiID
select new { api, dbml }
In order to get DbmlObject "in" the ApiObject, you will need to either inherit ApiObject and construct a new one of that class, which includes the Dbml property, or create a entirely new class to return. If you need static typing this is the best you can do - of course you could (mis)use dynamic to get what you want.
In this case, you are mentioning (in comments) that the ApiObject class is from a third party library that you can't change - in this case I would probably choose to create a new type which takes an instance of both objects in the constructor and exposes the properties you need - a decorator. Yes, it looks like a lot of code, but it is not complex, good tools will autogenerate it for you - and you get the class that you need for your code to be succinct.
In case you want to go further with returning an IEnumerable<dynamic>, you could build a "combining dynamic" object based on DynamicObject that then responds to all the properties of ApiObject and DbmlObject - or just adds DbmlObject as a property. I am not saying this is the right way to go, it depends on what you need it for - remember you are losing type safety. Here is a simple example:
void Main()
{
dynamic dyn = new CombiningDynamic(new Foo { X = 3 }, new Bar { Y = 42 });
Console.WriteLine(dyn.X);
Console.WriteLine(dyn.Y);
}
public class Foo
{
public int X {get;set;}
}
public class Bar
{
public int Y { get;set;}
}
public class CombiningDynamic : DynamicObject
{
private object [] innerObjects;
public CombiningDynamic(params object [] innerObjects)
{
this.innerObjects = innerObjects;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
foreach(var instance in innerObjects)
{
Type t = instance.GetType();
PropertyInfo prop = t.GetProperty(binder.Name);
if (prop != null && prop.CanRead)
{
result = prop.GetValue(instance, null);
return true;
}
}
result = null;
return false;
}
}
Remember, this is example code. If you really go this way, you would want to perhaps override some more of the methods (TrySetMember, ...), and you most definetely would want to cache the reflection results so you don't need to walk the types each time - reflection is (comparatively) slow.
I have a set of custom data types that can be used to manipulate basic blocks of data. For example:
MyTypeA Foo = new MyTypeA();
Foo.ParseString(InputString);
if (Foo.Value > 4) return;
Some of these types define read-only properties that describe aspects of the types (for example a name, bit size, etc.).
In my custom framework I want to be able to provide these types to the user for use in their applications but I also want to give the user a list of the available types which they could easily bind to a combobox. My current approach:
public static class DataTypes
{
static ReadOnlyCollection<MyDataType> AvailableTypes;
static DataTypes()
{
List<MyDataType> Types = new List<MyDataType>();
Types.Add(new MyTypeA());
Types.Add(new MyTypeB());
AvailableTypes = new ReadOnlyCollection<MyDataType>(Types);
}
}
What concerns me about this is that the user might obtain a type from the AvailableTypes list (by selecting a combobox item for example) and then use that reference directly rather than creating a clone of the type and using their own reference.
How can I make the list of available types read only so that it doesn't allow any writing or changes to the type instances, forcing the user to create their own clone?
Alternatively is there a better way of providing a list of available types?
Thanks, Andy
Make your custom Type class immutable, same as System.Type and you dont have to worry. A end user can fetch all the data it wants but he can not modify the object in any way.
EDIT: Example of immutable class
Take the following class for instance:
public class ImmutablePerson
{
private readonly string name; //readonly ensures the field can only be set in the object's constructor(s).
private readonly int age;
public ImmutablePerson(string name, int age)
{
this.name = name;
this.age = age;
}
public int Age { get { return this.age; } } //no setter
public string Name { get { return this.name; } }
public ImmutablePerson GrowUp(int years)
{
return new ImmutablePerson(this.name, this.age + years); //does not modify object state, it returns a new object with the new state.
}
}
ImmutablePerson is an immutable class. Once created there is no way a consumer can modify it in any way. Notice that the GrowUp(int years) method does not modify the state of the object at all, it just returns a new instance of ImmutablePerson with the new values.
I hope this helps you understand immutable objects a little better and how they can help you in your particular case.
To get around the problems you've mentioned, you could create a wrapper around your instances, and have the wrapper provide the functionality you require.
For example:
public class TypeDescriptor
{
private MyDataType _dataType;
public TypeDescriptor(MyDataType dataType)
{
_dataType = dataType;
}
public override string ToString()
{
return _dataType.ToString();
}
}
You class would then look something like:
public static class DataTypes
{
public static ReadOnlyCollection<TypeDescriptor> AvailableTypes;
static DataTypes()
{
List<TypeDescriptor> Types = new List<TypeDescriptor>();
Types.Add(new TypeDescriptor(new MyTypeA()));
Types.Add(new TypeDescriptor(new MyTypeB()));
AvailableTypes = new ReadOnlyCollection<TypeDescriptor>(Types);
}
}
Binding to the list and relying on the ToString() will now result in your data types ToString being called.
Create a list of types rather than a list of instances. e.g.
List<Type> Types = new List<Type>();
Types.Add(typeof(MyTypeA));
Types.Add(typeof(MyTypeB()));
etc.
To answer the comment on binding to a drop down list:
MyDropDown.Datasource = Type.Select(t => t.Name);
MyDropDown.DataBind();
This will not use the custom property of your classes but it will give you the simple calss name without all the other guff e.g. MyTypeA
A collection cannot "inject" type modifiers into its members. The collection you have declared is readonly. If you want MyDataType to be readonly you must declare that way.
Somthing like :
EDIT extended class to have a parse method
public class MyDataType
{
private MyDataType()
{
...
}
internal static MyDataType Parse(string someString)
{
MyDataType newOne = new MyDataType();
newOne.Value = ... //int.Parse(someString); ?
}
public int Value { get; private set; }
}
If the collection stays generic there is no readonly constraint.
You would use it like this, following your example.
MyTypeA foo = MyTypeA.Parse(inputString);
if (foo.Value > 4) return;
You probably shouldn't store instances of your types in the list. Instead you can store types. These can be used to create instances:
public static class DataTypes
{
static ReadOnlyCollection<Type> AvailableTypes;
static DataTypes()
{
List<Type> Types = new List<Type>();
Types.Add(typeof(MyTypeA));
Types.Add(typeof(MyTypeB));
AvailableTypes = new ReadOnlyCollection<MyDataType>(Type);
}
}
You can use Activator.CreateInstance to create a concrete instance:
Object myType = Activator.CreateInstance(AvailableTypes[0]);
Unless your types share a common base type you cannot downcast the result and an Object isn't that useful.
Also the use of the term type in your code makes my example a bit confusing as I suggest you store the types of something called type.
You could consider creating and attribute that you then can apply to MyTypeA, MyTypeB etc. Then you can build the AvailableTypes using reflection and the list will always be up to date with your code. E.g. if you add MyTypeC and use the attribute it will automatically be added to the list.
You can also add a display string property to the attribute and use that for display in the combo box. If you want to do that you should store a small object combining the type and the display string in AvailableTypes.
Here is an example. Using generic words like type and data can be confusing so to pick a random name I just use foo. Obviously you should use a more descriptive name.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
sealed class FooAttribute : Attribute {
public FooAttribute(String displayName) {
DisplayName = displayName;
}
public String DisplayName { get; private set; }
}
You can decorate you classes using this attribute:
[Foo("Type A")]
class MyTypeA { ... }
[Foo("Type B")]
class MyTypeB { ... }
For the combobox you want a list of factory objects with a nice ToString implementation (this class can be improved by adding some error handling which I have left out to save space):
class FooFactory {
readonly Type type;
public FooFactory(Type type) {
this.type = type;
DisplayName = ((FooAttribute) Attribute.GetCustomAttribute(
type,
typeof(FooAttribute))
).DisplayName;
}
public String DisplayName { get; private set; }
public Object CreateFoo() {
return Activator.CreateInstance(this.type);
}
public override String ToString() {
return DisplayName;
}
}
Returning Object from CreateFoo isn't very useful but that is a separate issue.
You can build this list at run-time:
var factories = Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => Attribute.IsDefined(t, typeof(FooAttribute)))
.Select(t => new FooFactory(t));
I'm not exactly sure of what you want but should something like this be ok ?
public static class DataTypes
{
static Dictionary<string,Type> AvailableTypes
= new Dictionary<string,Type>()
{
{ "MyTypeA", MyTypeA },
{ "MyTypeB", MyTypeB },
...
};
}
That is actually return types instead of sample instances of theses types. Thus you would be sure that only new instances would be created by the user of your class.
Then in the calling code :
MyTypeA a = Activator.CreateInstance(DataTypes.AvailableTypes["MyTypeA"]);