c# - Cast with GetType() and reflection - c#

So after implemented Page Object Pattern using this tutorial i have several
Pages that derived from BasePageElementMap.
And i want to handle some operation so i have this class:
public class DownloadAttachmentsHandler
{
public DownloadAttachmentsHandler(BasePageElementMap basePageElementMap)
{
Type type = basePageElementMap.GetType();
}
}
Every Pages that derived from BasePageElementMap have this html elements that locate inside its class that derived from BasePageElementMap and from this Page i have this Map object that contains all my HTML elements that i am using.
public class YahooEmailPage: BasePage<YahooEmailPageElementMap, YahooEmailPageValidator>...
so in case i am call this function like this:
UploadAttachmentsHandler att = new UploadAttachmentsHandler(new YahooEmailPage().Map);
I want to cast this into YahooEmailPage from my DownloadAttachmentsHandler method.
So currently i have this type object, how can i case it into YahooEmailPage ?

If I understood correctly, you want the following:
public class DownloadAttachmentsHandler
{
public static object Cast(object obj, Type t)
{
try
{
var param = Expression.Parameter(obj.GetType());
return Expression.Lambda(Expression.Convert(param, t), param)
.Compile().DynamicInvoke(obj);
}
catch (TargetInvocationException ex)
{
throw ex.InnerException;
}
}
public DownloadAttachmentsHandler(BasePageElementMap basePageElementMap)
{
Type type = basePageElementMap.GetType();
dynamic foo = Cast(basePageElementMap, type);
}
}
Based on this answer by balage.
EDIT: For the example, lets assume that GetType() returns the type bar. You will have to create a method like this one:
public static void UseDynamic(bar input)
{
// Stuff
}
And then do
public DownloadAttachmentsHandler(BasePageElementMap basePageElementMap)
{
Type type = basePageElementMap.GetType();
dynamic foo = Cast(basePageElementMap, type);
UseDynamic(foo);
}
You can use overloads to avoid having to write many ifs or a switch. However, whichever approach you take, you will have to create a method for each possible type.

Related

Return concrete type in abstract class

We have an abstract class BaseClass (note generic arg!) with a method called me.
Me returns this.
If we use Me in the concrete classes we will get a return type object.
Then we have to cast the result of Me to the type we originally are working with.
How can we achieve that Me returns the actual type of this? In this example type A?
public abstract class BaseClass<TIdentifier>{
public virtual object Me{ get { return this; } }
}
public class A: BaseClass<long>
{
}
public class B: BaseClass<long>
{
}
public class controller{
public void SomeMethod(){
var a = new A();
var b = new B();
var aObject = a.Me; // this will be of type object
var aObjectCasted = (A)aObject; // cast to original
// How I want it
var aConcrete = a.Me; // this returns type a
}
}
Update
Since some people really, desperately (wink:-)) wish to understand what I'm actually trying to do.
With NHibernate we are doing this:
var result = Session.Get<A>(idToLookUp);
In some cases it happens that result isn't of type A but is of type AProxy, due to laze loading etc. Now if we want to cast result to something else: we will get an invalidcastexception because the actual type of result isn't A but AProxy. And that type can't be casted. We can only cast type A to the other type.
A workaround for this is described here: http://sessionfactory.blogspot.be/2010/08/hacking-lazy-loaded-inheritance.html. That's where the Me property in the above examples comes in.
So to get result of type A and not of type AProxy we now have to do this:
var result = (A)Session.Get<A>(idToLookUp).Me;
Note we have to cast me back to type A if we want to get to read and know the property of result.
My question: can we get rid of the casting and adjust the Me property so we instantly return the concrete type?
Hope it's clear now.
You could use an interface on your derived classes:
public interface IStrongTypedMe<T>
{
T Me();
}
Your derived classes would become:
public class A: BaseClass<long>, IStrongTypedMe<A>
{
public new A Me()
{
return base.Me() as A;
}
}
This is assuming you can change A, of course.
Update:
I understand the issue now (only had time to read the linked article now).
Try using an extension method to do the casting for you like this:
public static TReturnType As<TReturnType,TIdentifier>(this BaseClass<TIdentifier> proxyObject)
where TReturnType : class
{
return proxyObject.Me as TReturnType;
}
And you'd use it like:
var result = Session.Get<A>(idToLookUp).As<A,long>();
No changes to A or B required.
You can change the return type of this property to the definition of parent class
public abstract class BaseClass<TIdentifier>
{
public virtual BaseClass<TIdentifier> Me{ get { return this; } }
}
If you want to return exactly the same class you can make some workaround by adding the result type in the generic type parameter
public abstract class BaseClass<TIdentifier, TMe>
where TMe : BaseClass<TIdentifier, TMe>, new()
{
public virtual TMe Me { get { return (TMe)this; } }
}
public class A : BaseClass<long, A>
{
}
Unfortunately, C#, unlike Java, does not support return type covariance. Otherwise you could just override the property Me in the subclasses like this to get what you want:
public abstract class BaseClass<TIdentifier> {
public virtual object Me { get { return this; } }
}
public class A: BaseClass<long>
{
public override A Me { get { return this; } } // wont work in C#
}
public class B: BaseClass<long>
{
public override B Me { get { return this; } } // wont work in C#
}
Mikhail Neofitov provides a good workaround though.
In order to do something like this:
var aObject = A.Me();
Me will need to be a static method.
A static method doesn't have a this.
If your not using a static method, you have the this - otherwise how are you willing to call the class method? You just need to cast it to the correct type.
Update Due To Edit:
You have this code:
var a = new A();
var aObject = a.Me;
Now what are you expecting here?
You have a which is from type A.
By using var you can't have multiple different return types from the Me geter.
The problem seems to be the implicit definition of the variable using var. When you are using var in this case, the compiler cannot determine the correct type for aObject in the editor. So take the following code for example:
public abstract class BaseClass<TIdentifier>
{
public virtual object Me {get {return this;} }
}
public class A : BaseClass<TIdentifier>
{
public int X
{
get {return 1;}
}
}
public class B : BaseClass<TIdentifier>
{
}
public class controller{
public void SomeMethod(){
var a = new A();
var b = new B();
var aObject = a.Me;
var aObjectCasted = (A)aObject;
// the environment cannot determine the correct type for aObject
// without compiling and running. At this time in the editor,
// this will be recognized as a type object. It will not
// understand aObject.X and will not compile
Console.WriteLine(aObject.X);
// During run-time, this will work. aObject will be defined as type A
Console.WriteLine(aObject.GetType().GetProperty("X").GetValue(aObject));
// this will output A for the type
Console.WriteLine(aObject.GetType());
}
}
Without being able to modify A and B, using the GetProperty, GetMethod, etc. methods on the implicitly defined variable seems like it will be your only hope.
Update:
You can reference this to see the types of calls you can make on a Type object. It seems like you will have to do this more dynamically that desired to achieve the functionality you want. The object will not be defined correctly before compiling if trying to do it implicitly.
var aConcrete = a.Me; in your code will indeed return yield a type A for aConcrete at compile time, but not in the editor.
From MSDN: "It is important to understand that the var keyword does not mean "variant" and does not indicate that the variable is loosely typed, or late-bound. It just means that the compiler determines and assigns the most appropriate type."

c# - can convert from C# type to System.Type but not vice-versa

I can create a generic class that takes, as its template parameter, a C# type, and then within the generic class use the System.Type information corresponding to that C# type:
public class Generic<T>
{
public bool IsArray()
{
return typeof(T).IsArray();
}
public T Create()
{
return blah();
}
}
Generic<int> gi = new Generic<int>();
Debug.WriteLine("int isarray=" + gi.IsArray());
Generic<DateTime> gdt;
But now let's say what I have, is a System.Type. I can't use this to instantiate my generic class:
FieldInfo field = foo();
Generic<field.FieldType> g; // Not valid!
Is there some clever C# thing I can do, to convert a System.Type back to the original C# type? Or some other way, to create a generic that can (1) give me information about the System.Type, and (2) create objects of the associate C# type?
By the way, this is a very contrived example to explain the problem I'm trying to solve, don't worry too much about whether Generic makes sense or not!
The only thing you can do is use reflection. This because while the int of Generic<int> is known at compile-time, the field.FieldType is known only at runtime.
Reflection example:
Type type = typeof(Generic<>).MakeGenericType(field.FieldType);
// Object of type Generic<field.FieldType>
object gen = Activator.CreateInstance(type);
But even here, from a Type (field.FieldType) you obtain another Type (type)
There are normally three ways of using this:
Full reflection: you use the object of type Generic<type> only through reflection. You create it through Activator.CreateInstance and from there you begin using Type.GetMethod() and Invoke()
Type type = typeof(Generic<>).MakeGenericType(field.FieldType);
// Object of type Generic<field.FieldType>
object gen = Activator.CreateInstance(type);
MethodInfo isArray = type.GetMethod("IsArray");
bool result = (bool)isArray.Invoke(gen, null);
Interfaces/base classes: you have a non-generic base class or interface that is common between all the Generic<T>. You use your object only though that interface/base class.
public class Generic<T> : IComparable where T : new()
{
public bool IsArray()
{
return typeof(T).IsArray;
}
public T Create()
{
return new T();
}
public int CompareTo(object obj)
{
return 0;
}
}
Type type = typeof(Generic<>).MakeGenericType(field.FieldType);
IComparable cmp = (IComparable)Activator.CreateInstance(type);
int res = cmp.CompareTo(cmp);
A generic method where you put all the handling of the Generic<T>. That is the only method that is used through reflection.
public static void WorkWithT<T>() where T : new()
{
Generic<T> g = new Generic<T>();
T obj = g.Create();
Console.WriteLine(g.IsArray());
}
var method = typeof(Program).GetMethod("WorkWithT").MakeGenericMethod(field.FieldType);
// Single reflection use. Inside WorkWithT no reflection is used.
method.Invoke(null, null);

Return instance using reflection in C#

A sample code I tried to return an instance of class is given below.
public object getConstructorclass(int i)
{
if(i==1)
{
Type type = Type.GetType("test1");
}else
{
Type type = Type.GetType("test2");
}
return Activator.CreateInstance(type);
}
var objcls = getConstructorclass(1);
objcls.callclass();//error occured
How can I mention the class type here since the type is not known at compile time but it will decided at runtime.In the above example i just pass a value 1 (it can be anything and that class will be called accordingly), and the class test1 called.
here I will get an error on the line objcls.callclass(), because objcls is an object instance that doesn't have a callclass()method.
How can I restructure this piece of code? My aim is if I mention a class in the getConstructorclass() method, an object should be returned so as to use it in the further code to invoke the members of that class.
If you know that your classes will have this method, you should use a common interface for them and implement it accordingly. Then you will work with classes that you have made sure it will work.
It would look like this
IMyInterface objcls = getconstrorclass() as IMyInterface;
if (objcls != null)
objcls.callclass();
else
// we failed miserably and should do something about it
I don't think you should use some generic object returning constructor based on an int variable, if your classes don't have anything in common. It's really weird to handle it like this and it may lead to various problems (some of which you're currently already experiencing). Generic class constructors make sense if the classes are somewhat related and you can predict the outcome, but to create a do-it-all method.. Not so sure about correctness of such approach.
Anyway, if you insist (not recommended, but as you wish), you can create some checks for a type like this:
var createdObject = getConstructorclass(1);
if (createdObject is MyClass1)
{
var specificObject = (MyClass1)createdObject;
specificObject.callMethod1();
}
else if (createdObject is MyClass2)
{
var specificObject = (MyClass2)createdObject;
specificObject.callSomeOtherMethod();
}
...
But it gets very error prone soon, refactoring will probably be a nightmare etc., but it's your call..
Or you maybe can use solution from pwas, but to me it seems unnecessarily complicated for such a basic task. Looks nice and all, but it still returns only the type "object", so it doesn't really solve your specific problem.
Also, to address one issue I'm not sure you understand - you've already created the instance, you just return type object. That is why you can't call any specific methods on this object, because first you have to cast it to something, that actually has that method and make sure the cast can be done (inheritance etc).
If interface solution (see other answers) is enough, don't look at this answer. When you can't use common base class / interface and you still want call members, you can use solution with is keyword (and check types). Instead of writing many ifs for each case, you can use fluent API:
object obj = this.getConstructorclass();
obj.StronglyInvoke()
.When<int>(value => Console.WriteLine("Got {0} as int", value))
.When<string>(value => Console.WriteLine("Got {0} as string", value))
.OnFail(() => Debug.Write("No handle."))
.Invoke();
Solution:
public class GenericCaller
{
private IList<GenericInvoker> invokers = new List<GenericInvoker>();
private readonly object target;
private Action failAction;
public GenericCaller(object target)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
this.target = target;
}
public GenericCaller OnFail(Action fail)
{
this.failAction = fail;
return this;
}
public GenericCaller When<T>(Action<T> then)
{
if (then == null)
{
throw new ArgumentNullException("then");
}
var invoker = new GenericInvoker<T>(this.target, then);
this.invokers.Add(invoker);
return this;
}
public void Invoke()
{
if (this.invokers.Any(invoker => invoker.Invoke()))
{
return;
}
if (this.failAction == null)
{
throw new InvalidOperationException("Handler not found");
}
this.failAction();
}
public abstract class GenericInvoker
{
protected readonly object target;
protected GenericInvoker(object target)
{
this.target = target;
}
public abstract bool Invoke();
}
public class GenericInvoker<T> : GenericInvoker
{
private readonly Action<T> then;
public GenericInvoker(object target, Action<T> then)
: base(target)
{
this.then = then;
}
public override bool Invoke()
{
if (this.target.GetType() == typeof(T))
{
this.then((T)this.target);
return true;
}
return false;
}
}
}
public static class Extensions
{
public static GenericCaller StronglyInvoke(this object o)
{
return new GenericCaller(o);
}
}
Remeber - it would be more elegant to use common interface (as other answers say) - my is only alternative way.
Declare your variable as dynamic
dynamic objcls = getconstrorclass();
Using this the will be determined at run-time, whatever the getconstrorclass method returns. You can access any member of the type and you won't get any error at compile-time. But if you try to access a member which doesn't exists you will get a RuntimeBinderException at runtime.
I would recommend using an interface and restricting the classes that you can instantiate this way to only those that implement the interface.
public interface IMyInterface
{
void callclass();
}
public <T> getConstructorClass()
{
T instance;
Type type = Type.GetType("test1");
// instance will be null if the object cannot be cast to type T.
instance = Activator.CreateInstance(type) as T;
return T;
}
IMyInterface objcls = getConstructorClass<IMyInterface>();
if(null != objcls)
{
objcls.callclass();
}
not sure what you want to achieve in the end, but this looks like a job for "Dependency Injection" - here is a nice sample using autofac

How to instantiate Generic class object?

I am trying to convert the following c# code into java
abstract class BaseProcessor<T> where T : new()
{
public T Process(HtmlDocument html)
{
T data = new T();
Type type = data.GetType();
BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty;
PropertyInfo[] properties = type.GetProperties(flags);
foreach (PropertyInfo property in properties)
{
string value = "test";
type.InvokeMember(property.Name, flags, Type.DefaultBinder, data, new object[] { value });
}
}
}
So i have done upto
public class BaseProcessor<T>
{
public T Process(String m_doc)
{
T data = (T) new BaseProcessor<T>(); // this is not working
Document doc = Jsoup.parse(m_doc);
return data;
}
}
When i instantiate the data object its not acquiring the properties of the Generic class at runtime
let say for example when i hit the code its not getting properties of DecodeModel class
IDocProcessor<DecodeModel> p = new DecodeThisProcessor();
return p.Process(doc);
public interface IDocProcessor<T>
{
T Process(String webresponse);
}
public class DecodeThisProcessor extends BaseProcessor<DecodeModel> implements IDocProcessor<DecodeModel>
{
public void setup();
}
So please help me what will be the right syntax to instantiate generic object data
You cannot instantiate generics. The reason is that the type is not available at run-time, but actually replaced with Object by the compiler. So
T data = new T(); // Not valid in Java for a generics T!
would in fact be:
Object data = new Object(); // Obviously not the desired result
Read the Java Generics Tutorial wrt. to "type erasure" for details.
You will need to employ the factory pattern.
T data = factory.make();
where
public interface Factory<T> {
T make();
}
needs to be implemented and passed to the constructor. To make this work, you need a factory that knows how to instantiate the desired class!
A (rather obvious) variant is to put the factory method into your - abstract - class.
public abstract class BaseProcessor<T>
{
protected abstract T makeProcessor();
public T Process(String m_doc)
{
T data = makeProcessor(); // this is now working!
and when extending BaseProcessor implement it for the actual final type.
Tough luck; in Java the whole of Generics is strictly a compile-time artifact and the instantiation of the type parameters doesn't exist in the runtime. The usual workaround is to pass an instance of Class as a marker, which will allow you to reflectively create an object of that type. This is fraught with many pitfalls, but is the best you can get in Java.
You can do this:
public class BaseProcessor<T>
{
private Class<T> clazz;
public BaseProcessor(Class<T> clazz)
{
this.clazz = clazz;
}
public T Process(String m_doc)
{
T data = clazz.newInstance()
Document doc = Jsoup.parse(m_doc);
return data;
}
}
Hint: Make sure that T has a no-arg constructor.

Casting generic type instances created using Reflection

I'm creating instances of a generic type using reflection:
public interface IModelBuilder<TModel>
{
TModel BuildModel();
}
public class MyModel
{
public string Name { get; set; }
}
public class MyModelBuilder : IModelBuilder<MyModel>
{
public MyModel BuildModel()
{
throw new NotImplementedException();
}
}
At runtime all we know is the Type of model e.g. MyModel. I can find instances of the relevant model builder like so:
var modelBuilders = from t in Assembly.GetExecutingAssembly().GetTypes()
from i in t.GetInterfaces()
where i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(IModelBuilder<>)
&& i.GetGenericArguments()[0] == modelType
select t;
var builder = Activator.CreateInstance(modelBuilders.First());
But I'm not sure how I can then cast the instance as IModelBuilder<TModel> so I can call and work with the result of BuildModel().
Since modelType is just a Type instance, you can't do that automatically, since there is no non-generic API available. Various options:
1: use reflection, for example (untested)
object builder = Activator.CreateInstance(...);
var model=builder.GetType().GetMethod("BuildModel").Invoke(builder,null);
2: cheat with dynamic:
dynamic builder = Activator.CreateInstance(...);
var model = builder.BuildModel();
3: make a non-generic version of IModelBuilder, and use that
Note that 1 & 2 rely on a public implementation of the interface, and will fail for a (perfectly legal) explicit interface implementation. For "1", you can fix this via:
var model = typeof(IModelBuilder<>).MakeGenericType(modelType)
.GetMethod("BuildModel").Invoke(builder);
A final sneaky option is to flip from a non-generic method into a generic method, so inside the generic method you can use all the members directly. There's a lazy way to do that via dynamic:
interface ISneaky<T>
{
T Foo { get; }
}
class Sneaky<T> : ISneaky<T>
{
T ISneaky<T>.Foo { get { return default(T); } }
}
class Program
{
static void Main()
{
Execute(typeof(int));
}
static void Execute(Type t)
{
dynamic obj = Activator.CreateInstance(
typeof(Sneaky<>).MakeGenericType(t));
// crafy hack to flip from non-generic code into generic code:
Evil(obj);
}
static void Evil<T>(ISneaky<T> sneaky)
{ // in here, life is simple; no more reflection
Console.WriteLine("{0}: {1}", typeof(T).Name, sneaky.Foo);
}
}

Categories