My question is very similar to the one asked here, but I was unable to find a solution based on the provided answers. I must be missing something that's right around the corner.
I have a custom converter that allows me to do the following:
cfg.CreateMap<Container<int>, int>().ConvertUsing(new ContainerConverter<Container<int>, int>());
But int being not the only type argument, is there a concise way to express:
cfg.CreateMap<Container<T>, T>().ConvertUsing(new ContainerConverter<Container<T>, T>());
Without having to do:
cfg.CreateMap<Container<int>, int>().ConvertUsing(new ContainerConverter<Container<int>, int>());
cfg.CreateMap<Container<long>, long>().ConvertUsing(new ContainerConverter<Container<long>, long>());
...
For every T in use?
In my situation, properties of Container<T> and T are in turn members of classes A1, A2... and B1, B2.... The mapping is performed by calling
B dest = mapper.Map<A, B>(source);
Thank you in advance.
If you don't mind the boxing, you can use a generic converter.
static void Main(string[] args)
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap(typeof(Container<>), typeof(object)).ConvertUsing(typeof(ContainerConverter<>));
});
config.AssertConfigurationIsValid();
//config.BuildExecutionPlan(typeof(Destination), typeof(Source)).ToReadableString().Dump();
var mapper = config.CreateMapper();
mapper.Map<int>(new Container<int>{ Value = 12 }).Dump();
}
public class ContainerConverter<T> : ITypeConverter<Container<T>, object>
{
public object Convert(Container<T> source, object destination, ResolutionContext c)
{
return source.Value;
}
}
public class Container<T>
{
public T Value { get; set; }
}
Related
I want to map between two classes:
public class A {
public IEnumerable<C> someList
}
and
public class B {
public RepeatedField<D> someList
}
where RepeatedField is a class from Google.Protobuf.Collections that handles gRPC data.
EDIT: As it turns out, the way that gRPC creates classes via its prototype is not exactly like creating a class like B. See my answer.
I create an Automapper MappingConfiguration like this
return new MapperConfiguration(cfg =>
{
cfg.CreateMap<C, D>().ReverseMap();
cfg.CreateMap<A, B>().ReverseMap();
});
and then it gets registered via ASP.NET Startup class.
If I do something like this in another class
A instanceA; // assume A's list has values inside
var listofD = this.mapper.Map<List<D>>(A.someList)
it correctly returns a list with values inside. However:
A instanceA; // assume A's list has values inside
B instanceB = this.mapper.Map<B>(A);
returns an instance of B, but the list inside of instanceB is empty. How do I fix this?
You need to create a custom type converter for performing the conversion:
private class EnumerableToRepeatedFieldTypeConverter<TITemSource, TITemDest> : ITypeConverter<IEnumerable<TITemSource>, RepeatedField<TITemDest>>
{
public RepeatedField<TITemDest> Convert(IEnumerable<TITemSource> source, RepeatedField<TITemDest> destination, ResolutionContext context)
{
destination = destination ?? new RepeatedField<TITemDest>();
foreach (var item in source)
{
// obviously we haven't performed the mapping for the item yet
// since AutoMapper didn't recognise the list conversion
// so we need to map the item here and then add it to the new
// collection
destination.Add(context.Mapper.Map<TITemDest>(item));
}
return destination;
}
}
And the other way, if required:
private class RepeatedFieldToListTypeConverter<TITemSource, TITemDest> : ITypeConverter<RepeatedField<TITemSource>, List<TITemDest>>
{
public List<TITemDest> Convert(RepeatedField<TITemSource> source, List<TITemDest> destination, ResolutionContext context)
{
destination = destination ?? new List<TITemDest>();
foreach (var item in source)
{
destination.Add(context.Mapper.Map<TITemDest>(item));
}
return destination;
}
}
Which you can register like so:
ce.CreateMap(typeof(IEnumerable<>), typeof(RepeatedField<>)).ConvertUsing(typeof(EnumerableToRepeatedFieldTypeConverter<,>));
ce.CreateMap(typeof(RepeatedField<>), typeof(List<>)).ConvertUsing(typeof(RepeatedFieldToListTypeConverter<,>));
Try it online
I've solved the issue.
A Google.Protobuf.Collections.RepeatedField inside a C# class is readonly, meaning that directly assigning values into it won't work and will only return an empty list on the way back. Therefore, I created a custom type converter between the two larger classes to bring them together. What it does is add values directly into the RepeatedField rather than populating my own RepeatedField and assigning the value into the class.
public static class mapConfig
{
public static ContainerBuilder RegisterObjectMappers(this ContainerBuilder builder)
{
builder.Register(c => GetV1MapperConfiguration().CreateMapper())
.As<IMapper>().SingleInstance();
return builder;
}
private static MapperConfiguration GetMapConfig()
{
return new MapperConfiguration(cfg =>
{
// some mappings here
cfg.CreateMap<C, D>().ReverseMap();
cfg.CreateMap<A, B>().ConvertUsing<AToBConverter>();
});
}
}
public class AToBConverter : ITypeConverter<A, B>
{
public B Convert(A source, B destination, ResolutionContext context)
{
var b = new B
{
// internal values here aside from the repeated field(s)
};
// Need to use the Add method to add values rather than assign it with an '=' sign
foreach (var someValue in source.someList)
{
b.someList.Add(context.Mapper.Map<D>(someValue));
}
return b;
}
}
Converting from RepeatedField to a List or any other IEnumerable in a mapped class isn't any trouble and didn't require another converter for me.
I want to instantiate a generic list of objects like:
public static class TablesClass
{
private static IList<Tables<T>> TablesInstance { get; set; }
static TablesClass() => Tables = new List<Tables<T>>();
public static void AddTable(Table<t> table) => Tables.Add(table);
}
I can't change Tables<T>, this is a nuget package class.
How may i achieve this? All i have tried just does not work (setting a type T to class, using object instead T and casts - not desired solution).
Can somebody help me?
TablesClass is not a generic class and you are not telling the compiler what type T is supposed to be somewhere.
If you want to be able to add different kinds of objects into the same IList<Tables<T>> list, T must be a common base type for all these objects.
For example, if you want to be able to add apples, pears and bananas to the list, the type parameter T may be specified as Fruit provided that Fruit is the base class for all these types.
Obviously you will need to cast from Fruit if you want to be able to access any member of an item in the list that is specific to a concrete implementation of Fruit class but this is inevitable. You don't throw a bunch of different kinds of fruits into a single basket and expect to be able to always pick up a specific fruit, do you?
Your nuget class must be this style:
public abstract class Tables
{
}
//the Generic class must has a base, by which you can list them
public class Tables<T> : Tables // where T: something base class of your object
{
//...
}
then your class must be:
public static class TablesClass
{
//Search source code of your Nuget package, find its base class of Generic class, the list must be defined as its base
private static IList<Tables> Tables { get; set; }
static TablesClass()
{
Tables = new List<Tables>();
}
public static void AddTable(Tables table)
{
Tables.Add(table);
}
}
then you can use it like this:
public class Test
{
public static void Mains()
{
TablesClass.AddTable(new Tables<A>());
TablesClass.AddTable(new Tables<B>());
TablesClass.AddTable(new Tables<C>());
}
}
If you want to do this kind of thing you need to hold the references using object, but make a method that allows you to store and fetch each table using strong-typing.
Try a class like this:
public class Repository
{
private Dictionary<Type, Dictionary<string, object>> _store
= new Dictionary<Type, Dictionary<string, object>>();
public void Store<T>(string key, T value)
{
if (!_store.ContainsKey(typeof(T)))
{
_store.Add(typeof(T), new Dictionary<string, object>());
}
_store[typeof(T)][key] = value;
}
public T Fetch<T>(string key)
{
return (T)_store[typeof(T)][key];
}
public bool TryFetch<T>(string key, out T value)
{
var success = _store.ContainsKey(typeof(T)) && _store[typeof(T)].ContainsKey(key);
value = success ? this.Fetch<T>(key) : default(T);
return success;
}
public bool TryInject<T>(string key, Action<T> inject)
{
var success = this.TryFetch<T>(key, out T value);
if (success)
{
inject(value);
}
return success;
}
}
Then you can strongly-type the objects into the repository (collection) and strongly-type fetching them out like this:
var repository = new Repository();
repository.Store("a", new TableA());
repository.Store("b", new TableB());
repository.Store("c", new TableC());
repository.Store("d", new TableD());
/* Somewhere else in your code */
TableA a = repository.Fetch<TableA>("a");
TableB b = repository.Fetch<TableB>("b");
TableC c = repository.Fetch<TableC>("c");
TableD d = repository.Fetch<TableD>("d");
The key value (i.e. "a") is optional - you can remove it from the code - but it is useful if you need to store more that one object of a specific type.
Way much simple solution: List<dynamic>.
This is what I am trying to get
(IList<Foo>)listPropertyInfo.GetValue(item)
This is how I get Foo type
listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]
This is what I tried but couldn't make it successfully
Convert.ChangeType(listPropertyInfo.GetValue(item), IList<listPropertyInfo.GetValue(item).GetType().GenericTypeArguments[0]>)
and also this;
((typeof(IList<>).MakeGenericType(listPropertyInfo.GetValue(item).GetType().GenericTypeArguments.Single())))(listPropertyInfo.GetValue(item))
this is method where I am trying to implement
public static void trigger(IList<T> result)
{
foreach (var item in result)
{
foreach (var listPropertyInfo in typeof(T).GetProperties().ToList().FindAll(x => x.PropertyType.Name == typeof(IList<>).Name))
{
trigger((IList<Foo>)listPropertyInfo.GetValue(item));
}
}
}
I solved like this;
IList targetList = (IList)listPropertyInfo.GetValue(item);
Type foo = targetList.GetType().GenericTypeArguments.Single();
Type unboundGenericType = typeof(READ<>);
Type boundGenericType = unboundGenericType.MakeGenericType(foo);
MethodInfo doSomethingMethod = boundGenericType.GetMethod("trigger");
object instance = Activator.CreateInstance(boundGenericType);
doSomethingMethod.Invoke(instance, new object[] { targetList, f, properties });
If you use IList notation, Foo must be defined at compile time, you can't use expression that evaluates at runtime for Foo.
After reading your comments and and the code i would argue you are trying to do it at the wrong spot.
Here an example of how you could do this
public class MyGeneric<T>
{
public static void trigger(IList<T> result)
{
// do generic stuff where
// you do not need to know T
}
}
// this class does only explicit Foo related stuff
public class MyNONEGeneric
{
public static void trigger(IList<Foo> list)
{
// do some
}
}
class Program
{
static void Main(string[] args)
{
PersistentGenericBag<Foo> magicBag = myMagic<Foo>();
// call your generic which do some general list related stuff
MyGeneric<Foo>.trigger(list);
// call your none generic which do some foo related stuff
MyNONEGeneric.trigger(list);
}
}
like you can see i did some sort of "separation of concerns" / "single responsibility principle" here.
Every thing does only "one" thing. so if you are in need to change something you will know exactly where.
Also if you are working in a Team you can tell Person A to do the MyGeneric<T> and Person B to do the MyNONEGeneric
This is my Scenario:
public class Foo
{
private readonly List<Lazy<IAnimal>> _animals;
public Foo(List<Lazy<IAnimal>> animals )
{
_animals = animals;
}
public void Bark()
{
//Line: *
var dog = _animals.First(p => p.GetType() == typeof (Dog)).Value;
}
Public void Mio()
{
//Line: *
var dog = _animals.First(p => p.GetType() == typeof (Cat)).Value;
}
}
public class Dog:IAnimal
{
}
public class Cat:IAnimal
{
}
public interface IAnimal
{
}
Questions:
Here The list of Animals are Lazily injected into the class Foo.
I want to do something like Line * with Ninject. As you may know the problem is that before resolving a class, GetType() returns Null. So how can I resolve just one of the Items in the list whenever I want?
Can Ninject do such a thing at all or I have to change my DI Container?
This is a chicken and the egg problem: you don't know the type unless you get the value. You can only solve this by adding extra information to the list that is known before hand.
This is a good fit for Lazy<T, TMetadata> which is part of the System.ComponentModel.Composition assembly:
public class Foo
{
private readonly List<Lazy<IAnimal, Type>> _animals;
public Foo(List<Lazy<IAnimal, Type>> animals)
{
_animals = animals;
}
public void Bark()
{
var dog = _animals.First(p => p.Metadata == typeof(Dog)).Value;
}
}
Update
As I said in the comments, I'm no Ninject expert, but most things can be done with a framework, even when there is no built-in support for it. This is what I think your registration would look like. I might have the Ninject syntax wrong, but it would look a bit like this:
var list = new List<Lazy<IAnimal, Type>>();
list.Add(new Lazy<IAnimal, Type>(() => kernel.Get<Dog>(), typeof(Dog)));
list.Add(new Lazy<IAnimal, Type>(() => kernel.Get<Pussy>(), typeof(Pussy)));
list.Add(new Lazy<IAnimal, Type>(() => kernel.Get<Horse>(), typeof(Horse)));
kernel.Bind<List<Lazy<IAnimal, Type>>().ToConstant(list);
You can use the OfType extension method provided in the System.Linq namespace.
var dog = _animals.OfType<Dog>().First();
I find myself (too) often using a construct like the following:
class MyClass
{
public TypeA ObjectA;
public TypeB ObjectB;
public TypeC ObjectC;
public List<TypeD> ListOfObjectD = new List<TypeD>();
public void DoSmth()
{
return SomeConstruct(
/*...*/
new Setter<TypeA>(a => ObjectA = a), // these are the
new Setter<TypeB>(b => ObjectB = b), // things I'm trying
new Setter<TypeC>(c => ObjectC = c), // to make shorter
new Setter<TypeD>(d => ListOfObjectD.Add(d)),
/*...*/
);
}
}
class Setter<T>
{
public Action<T> Action;
public Setter(Action<T> action)
{
Action = action;
}
}
Is there any way for the Setter class to infer the type of the Action and create the standard (T obj) => Member = obj Action by only passing the Member in some way? I'm thinking of something like:
new Setter(ObjectA)
which of course is not valid syntax, but should give you an idea what I'm trying to achieve. I'm using this construct literally hundreds of time in my code, so the code
saved by this small change would be tremendous.
Edit: Added the TypeD example. The part
new Setter<TypeD>(d => ListOfObjectD.Add(d))
can be simplified to
new Setter<TypeD>(ListOfObjectD.Add)
which is awesome because it cuts from the redundant code. If only <TypeD> could also be inferred it would be perfect. I'm looking for something like this for the others.
#Lazarus - basically the purpose is to return setters, so other objects can set certain members of the class (or it can do other stuff defined in the Action) without accessing the class itself, only the Setter object. The full list of reasons is long and convoluted, but the structuring of the program works like a charm and I doubt needs changing (the example of course is simplified and doesn't really make sense as is).
Edit 2: I found a good way to simplify things for List's:
static class SetterHelper
{
public static Setter<T> GetSetter<T>(this List<T> list)
{
return new Setter<T>(list.Add);
}
}
Now I can just use this:
ListOfObjectD.GetSetter()
which works perfectly! why can't I do the same for T directly? I tried this:
static class SetterHelper
{
public static Setter<T> GetSetter<T>(this T item)
{
return new Setter<T>(t => item = t); // THIS DOESN'T SET THE PASSED MEMBER
}
}
Of course it won't work as intended because it will set item, but not the passed member. I tried adding ref as (ref this T item) but it won't compile :(... It would have been perfect.
Best I can offer you is the following syntax:
Setter.For( () => ObjectA );
using this helper class
static class Setter
{
public static Setter<T> For<T>(Expression<Func<T>> e)
{
ParameterExpression[] args = { Expression.Parameter(((e.Body as MemberExpression).Member as FieldInfo).FieldType) };
Action<T> s = Expression.Lambda<Action<T>>(Expression.Assign(e.Body, args[0]), args).Compile();
return new Setter<T>(s);
}
}