I want to add an item to a Generic list using reflection. In the method "DoSomething", I am trying to finish the following line,
pi.PropertyType.GetMethod("Add").Invoke(??????)
but I am getting different kinds of error.
Below is my complete code
public class MyBaseClass
{
public int VechicleId { get; set; }
}
public class Car:MyBaseClass
{
public string Make { get; set; }
}
public class Bike : MyBaseClass
{
public int CC { get; set; }
}
public class Main
{
public string AgencyName { get; set; }
public MyBaseCollection<Car> lstCar {get;set;}
public void DoSomething()
{
PropertyInfo[] p =this.GetType().GetProperties();
foreach (PropertyInfo pi in p)
{
if (pi.PropertyType.Name.Contains("MyBaseCollection"))
{
//Cln contains List<Car>
IEnumerable<MyBaseClass> cln = pi.GetValue(this, null) as IEnumerable<MyBaseClass>;
**//Now using reflection i want to add a new car to my object this.MyBaseCollection**
pi.PropertyType.GetMethod("Add").Invoke(??????)
}
}
}
}
Any ideas / suggestion ?
I think you want:
// Cast to IEnumerable<MyBaseClass> isn't helping you, so why bother?
object cln = pi.GetValue(this, null);
// Create myBaseClassInstance.
// (How will you do this though, if you don't know the element-type?)
MyBaseClass myBaseClassInstance = ...
// Invoke Add method on 'cln', passing 'myBaseClassInstance' as the only argument.
pi.PropertyType.GetMethod("Add").Invoke(cln, new[] { myBaseClassInstance } );
Since you don't know what the element-type of the collection is going to be (could be Car, Bike, Cycle etc.) you're going to find it hard to find a useful cast. For example, although you say the collection will definitely implement IList<SomeMyBaseClassSubType>, that isn't all that helpful since IList<T> isn't covariant. Of course, casting to IEnumerable<MyBaseClass> should succeed, but that won't help you since it doesn't support mutations. On the other hand, if your collection-type implemented the non-generic IList or ICollection types, casting to those might come in handy.
But if you're sure that the collection will implement IList<Car> (i.e. you know the element-type of the collection beforehand), things are easier:
// A much more useful cast.
IList<Car> cln = (IList<Car>)pi.GetValue(this, null);
// Create car.
Car car = ...
// The cast helped!
cln.Add(car);
As an alternative... Just don't; consider the non-generic IList interface:
IList list = (IList) {... get value ...}
list.Add(newItem);
While it isn't obligatory for all generic collections to implement IList, they pretty much all do, since it underpins such a lot of core framework code.
start with typeof<List<>>.GetMethods, you do not invoke a method of the property, but a method of the type of the property
Could you just avoid reflection all together and use:
List<MyBaseClass> lstCar { get; set; }
lstCar.Add((MyBaseClass)new Car());
You could also consider using an interface or abstract methods...
Related
I need to cast a class list to its own interface list.
So I have interface Demo_Interface and two classes based on Demo_Interface ,
Now I create list of classes like List<Test_Class1>
And I have a function with List<Demo_Interface> parameter.
Here's interface :
interface Demo_Interface
{
int test_int { get; set; }
}
Here's Entire Code :
using System;
using System.Collections.Generic;
namespace ConsoleApp3
{
class Program
{
///// Main Interface
interface Demo_Interface
{
int test_int { get; set; }
}
//// Class 1 Based On Demo_Interface
class Test_Class1 : Demo_Interface
{
public int test_int { get; set; }
public string test_string { get; set; }
}
///// Class 2 Based On Demo_Interface
class Test_Class2 : Demo_Interface
{
public int test_int { get; set; }
public string test_string { get; set; }
}
//// And Main Class
class Main_Class
{
public List<Test_Class1> class_list_1 { get; set; }
public List<Test_Class2> class_list_2 { get; set; }
public Main_Class()
{
class_list_1 = new List<Test_Class1>() { };
class_list_2 = new List<Test_Class2>() { };
}
}
//// Console Main
static void Main(string[] args)
{
var new_main_class = new Main_Class();
Output_Class(new_main_class.class_list_1); ///// ==> ERROR
Console.ReadKey();
}
//// Simple Function for do something with interface
static void Output_Class(List<Demo_Interface> inter_input)
{
for (int i = 0; i < inter_input.Count; i++)
{
Console.WriteLine("{0} - {1}",i, inter_input[i].test_int);
}
}
}
}
How Can I cast List<Test_Class1> to List<Demo_Interface> , When Test_Class1 uses Demo_Interface?
You can try
List<Test_Class1> testDemo = new List<Test_Class1>(); //list of Test_Class1 instances
List<Demo_Interface> result = testDemo.ToList<Demo_Interface>();
This is safe because we are not directly casting testDemo to its interface. We are keeping testDemo as it is and we are creating result which is list of Demo_Interface
You cannot cast a List<ClassThatImplementsInterface> as a List<IInterfaceItImplements>.
If you could, and you did this:
var classList = new List<ClassThatImplementsInterface>();
var interfaceList = (List<IInterfaceItImplements>)classList;
... then you would be able to do this:
interfaceList.Add(new SomeOtherClassThatImplementsTheInterface);
But casting the list doesn't create a new list. In the above example there aren't two lists. There are two variables with references to the same list. If you could cast as seen above, you would be able to define a list of one type and add a completely different type to it. The compiler prevents that.
You could
create a new List<IDemoInterface> and add the items to it. (Or an array, IEnumerable, etc.)
Leave the list as-is, and just cast individual items when/if you need to. In most cases we wouldn't need to cast something as an interface it implements.
If we need to cast a whole collection as a different type, it's likely because we're passing it as an argument.
That's actually a good reason not to define a method argument as a collection type like a List<T> which can be modified unless it's our intent to modify the collection.
That's one reason why we pass less-specific collection types, like IEnumerable<T>.
Suppose the method argument looks like this:
void MethodINeedToPassTheArgumentTo(IEnumerable<IDemoInterface> items)
Now we can take our List<TestClass> and do this:
MethodINeedToPassTheArgumentTo(testClassList.Cast<IDemoInterface>);
We're not creating a new collection. We're passing a reference that allows the other method to view the items in the list, each individually cast as IDemoInterface. For practical purposes it looks to the other method like a collection of IDemoInterface, and that's okay because the other item can't modify the collection. It can't attempt to add other types into the List<TestClass>.
If you need only to enumerate through the List<Demo_Interface> like shown in example, you don't have to do any kind of explicit casting. List<T> implements IEnumerable<T> which is covariant generic type.
Covariance for collections enables implicit conversion of a collection of a more derived type to a collection of a less derived type
In your case, List<Test_Class1> implements IEnumerable<Test_Class1>, but since Test_Class1 implements Demo_Interface, you can take advantage of generics variance and write, for example, something like this:
IEnumerable<Test_Class1> col = new List<Test_Class1>();
IEnumerable<Demo_Interface> colImplicit = col;
That basically means that your Output_Class method can take IEnumerable<Demo_Interface> argument and you'll be able to pass both lists without casting them explicitly using Cast<T> or creating a new collection using ToList<T>.
private void Output_Class(IEnumerable<Demo_Interface> inter_input)
{
// do your thing
}
// Method invocation
Output_Class(new_main_class.class_list_1);
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.
public class ConfigControlBase<T> : UserControl
where T : ProviderBase
{
public T Provider { get; set; }
public void Init(T provider)
{
this.Provider = provider;
}
}
public abstract class ProviderBase
{
public abstract ConfigControlBase<ProviderBase> GetControl();
}
public class ProviderXConfigControl : ConfigControlBase<ProviderX>
{
}
public class ProviderX : ProviderBase
{
public override ConfigControlBase<ProviderBase> GetControl()
{
var confControl = new ProviderXConfigControl() as ConfigControlBase<ProviderX>;
return confControl;
}
}
return confControl; throws an exception:
Cannot implicitly convert type ConfigControlBase<ProviderX> to ConfigControlBase<ProviderBase>
Let's change the name of your classes and properties, but keep the shape the same:
public class Cage<T> where T : Animal
{
public T Contents { get; set; }
}
public class Aquarium : Cage<Fish> { }
public abstract class Animal
{
public abstract Cage<Animal> GetCage();
}
public class Fish : Animal
{
public override Cage<Animal> GetCage()
{
return (Cage<Animal>)(new Aquarium());
}
}
Now is it clear why this is not legal? Suppose it were legal. Then you could do this:
Fish fish = new Fish();
Cage<Animal> cage = fish.GetCage();
cage.contents = new Tiger();
And now you have a tiger in your aquarium. And no one wants that.
The compiler (or runtime) has to prevent this type error somehow; it chooses to prevent it as soon as possible. The earliest it can do so is on the type test for the conversion from Aquarium to Cage<Animal>. The compiler knows that this can eventually lead to tigers in aquariums, so it does not allow the conversion at all. If you force the compiler to allow it through casts then it fails at runtime.
Generic types with assignable type arguments are not assignable themselves.
For instance, you cannot cast List<string> to List<object>, although string is an object.
It is not immediately obvious why such casting is not supported so let me give you an example:
var words = new List<string> { "Serve God", "love me", "mend" };
var objects = (List<object>) words; // C# compiler wouldn't allow this
objects.Add (new Car()); // we just added a Car to Shakespeare's work and the universe exploded
C# doesn't encourage universe explosion, however since C# 4.0 a light version of this idea is implemented. You see, in some cases such casting would actually be safe.
.NET 4.0 brings concepts of covariance and contravariance in generics only for interfaces and delegates, you may want to check this out.
Example (doesn't work prior to .NET 4.0):
void HandleCollection (IEnumerable<object> collection)
{
// ...
}
var words = new List<string> { "Serve God", "love me", "mend" };
// IEnumerable is defined as IEnumerable<out T> in .NET 4.0
// 'out' keyword guarantees that T is only used for return values
// and therefore client code can't explode the universe
var objects = (IEnumerable<object>) words;
HandleCollection (objects);
This is because ConfigControlBase<ProviderX> is not a ConfigControlBase<ProviderBase>
your
public override ConfigControlBase<ProviderBase> GetControl()
doesn't match
var confControl = new ProviderXConfigControl() as ConfigControlBase<ProviderX>;
This answer might not be useful in your scenario, as you should probably look for another solution, but during reflection I found the ability to cast to less generic types very useful, hence I wrote a solution for it. It only works for interfaces however, and you do have to guarantee you will only pass objects of the correct types to the interface.
I basically generate a proxy class at runtime which does all the required casts for you. It's usage looks as follows:
object validator; // An object known to implement IValidation<T>.
object toValidate; // The object which can be validated by using the validator.
// Assume validator is IValidation<string> and toValidate a string.
IValidation<object> validation
= Proxy.CreateGenericInterfaceWrapper<IValidation<object>>( validator );
validation.IsValid( toValidate ); // This works! No need to know about the type.
// The following will throw an InvalidCastException.
//validation.IsValid( 10 );
More information and source code can be found on my blog.
There is already a similar question but it didn't seem to ask about the situation that the question implies.
The user asked about custom classes in a list but his list object is of type string.
I have a class Foo that has a list of Bars:
public class Foo : FooBase
{
public List<Bar> bars {get; set;}
public Foo() {}
}
public class Bar
{
public byte Id { get; set; }
public byte Status { get; set; }
public byte Type { get; set; }
public Bar(){}
}
I instantiate Foo using reflection via Activator.CreateInstance(). Now I need to populate that list of bars with Bar objects.
Foo is obtained using
Assembly.GetAssembly(FooBase).GetTypes().Where(type => type.IsSubclassOf(FooBase));
Bar is a public class in the same Assembly. I'll need to get at that type somehow. I can't seem to see what the type of the list contained in Foo is. I know it's a list though. I'm seeing the list property as List`1.
I'd need to see what type of object the list holds and handle that accordingly.
The text
List`1
is the way that generics are written under the bonnet - meaning "List with 1 generic type arg, aka List<>". If you have a PropertyInfo, you should be set; this will be the closed generic List<Bar>. Is it that you want to find the Bar given just this?
If so, this is discussed in various questions, including this one; to duplicate the key bit (I prefer to code against IList<T>, since it handles a few edge-cases such as inheriting from List<T>):
static Type GetListType(Type type) {
foreach (Type intType in type.GetInterfaces()) {
if (intType.IsGenericType
&& intType.GetGenericTypeDefinition() == typeof(IList<>)) {
return intType.GetGenericArguments()[0];
}
}
return null;
}
var prop = footype.GetProperty("bars");
// In case you want to retrieve the time of item in the list (but actually you don't need it...)
//var typeArguments = prop.PropertyType.GetGenericArguments();
//var listItemType = typeArguments[0];
var lst = Activator.CreateInstance(prop.PropertyType);
prop.SetValue(foo, lst, null);