I have 2 class which has a different constraint, and I want to create obj for them conditionally in a generic function. Example below.
public class Foo1<T>
where T : class, Interface1, new()
{
// do sth...
}
public class Foo2<T>
where T : class, Interface2, new()
{
//do sth...
}
public static void Create<T>()
{
if(typeof(Interface1).IsAssignableFrom(typeof(T))
{
var obj = new Foo1();
//...
} else if (typeof(Interface2).IsAssignableFrom(typeof(T))
{
var obj = new Foo1();
//...
}
}
And I got the error "There is no implicit reference conversion from T to Interface1/2".
The problem is similar to Similiar to How to conditionally invoke a generic method with constraints?, but I can find a place to add (dynamic).
You can create an instance of a generic class using reflection.
public static void Create<T>()
{
if (typeof(Interface1).IsAssignableFrom(typeof(T)))
{
var d1 = typeof(Foo1<>);
Type[] typeArgs = { typeof(T) };
var makeme = d1.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(makeme);
}
else if (typeof(Interface2).IsAssignableFrom(typeof(T))
{
// same for Foo2
}
}
Related
I don't if is possible create something like that:
async static Task method<T>(object obj = null) where T : SomeClass, new()
{
SomeClass s;
if (obj != null)
s = new T(obj);
else
s = new T();
}
I want to create a class in my method with default construct but sometimes it need an object given.
Update :
class A : SomeClass
{
public A() {
...
}
}
class B : SommeClass
{
public B(Object obj)
{
... //using obj
}
}
So, I have the following structure:
public abstract class MyBase
{
public Type TargetType { get; protected set; }
}
public class A : MyBase
{
public A()
{
TargetType = GetType();//Wrong, I need B class type not C
}
}
public class B : A
{
public B() { }
}
public class C : B
{
public C() { }
}
Of course, I can receive my type in this way:
public class B : A
{
public B()
{
TargetType = typeof(B);
}
}
Actually, I have to write some code to make the example clearer:
Class1.cs
public static Dictionary<Type, Type> MyTypes = new Dictionary<Type, Type>()
{
{ typeof(B),typeof(BView) }
}
public Class1()
{
C itemC = new C();
Class2.Initialize(itemC);
}
Class2.cs
public static Initialize(MyBase myBase)
{
Type t;
Class1.MyTypes.TryGetValue(myBase.TargetType, out t);
//I need get BView but I get null because *myBase.TargetType* is C class type
}
Level structure:
Level 0:(MyBase) - 1 object
Level 1:(A) - 2 objects
Level 2:(B) - 100 objects and more
Level 3:(C) - 80 objects and more
I gave this case in brackets
I will be grateful for any help
On any instance of an object you can call .GetType() to get the type of that object.
You don't need to set the type on construction
I didn't understand completely your question, but these are some possibilities to get informations about a type:
var a = new A();
Console.WriteLine(a.GetType().Name); // Output: A
Console.WriteLine(a.GetType().BaseType?.Name); // Output: MyBase
var b = new B();
Console.WriteLine(b.GetType().Name); // Output: B
Console.WriteLine(b.GetType().BaseType?.Name); // Output: A
// A simple loop to get to visit the derivance chain
var currentType = b.GetType();
while (currentType != typeof(object))
{
Console.WriteLine(currentType.Name);
currentType = currentType.BaseType;
}
// Output: B A MyBase
Also, I suggest to read this post about the difference between GetType and typeof
Hope this helps.
I have a bunch of classes that inherit from a single class. I'm using reflections to access the classes, since the ones that will be accessed will change in runtime.
But I am having some trouble when trying to invoke a method declared at superclass.
Here is my parent class:
public class ParentClass {
public ParentClass (Type type) {
}
public string method0String () {
return string;
}
public void method1Void (string) {
}
}
Here is my child class:
public class ChildClass : ParentClass {
public ParentClass () : base(typeof(ChildClass)) {
}
}
Here is the abstract class code where I cast the methods:
Type childType = Type.GetType(className[i]);
ConstructorInfo childConstructor = childType.GetConstructor(new Type[0]);
object childObject = null;
childObject = childConstructor.Invoke(childObject, new object[0]);
MethodInfo parentMethod0String = childType.GetMethod("method0String");
MethodInfo parentMethod1Void = childType.GetMethod("method1Void");
parentMethod1Void.Invoke(childObject, new object[]{argString});
object finalString = parentMethod0String.Invoke(childObject, new object[0]);
The MethodInfos are always null, which causes this error when I try to invoke them:
System.NullReferenceException: Object reference not set to an instance of an object
I haven't found anyway around this.
Basically, I just need to invoke a super method using the child as the dynamic object. How can I achieve this?
#Edit
After #nvoigt answer, my code looks like this:
Type childType = Type.GetType(className[i]);
object childObject = Activator.CreateInstance(childType);
Type parentType = Type.GetType("ParentClass");
MethodInfo parentMethod0String = parentType.GetMethod("method0String");
MethodInfo parentMethod1Void = parentType.GetMethod("method1Void");
parentMethod1Void.Invoke(childObject, new object[]{argString});
object finalString = parentMethod0String.Invoke(childObject, new object[0]);
And the error is a little different:
System.Reflection.TargetException: Object does not match target type.
You can do it this way:
namespace StackOverFlowTest
{
using System;
class BaseClass
{
public int BaseClassMethod(int x)
{
return x * x;
}
}
class DerivedClass : BaseClass
{
}
class Program
{
static void Main()
{
var derivedType = typeof(DerivedClass);
var baseType = typeof(BaseClass);
var method = baseType.GetMethod("BaseClassMethod");
var derivedInstance = Activator.CreateInstance(derivedType);
var result = method.Invoke(derivedInstance, new object[] { 42 });
Console.WriteLine(result);
Console.ReadLine();
}
}
}
Lets say I have a generic class:
class Foo {
// protected Type t;
// public void SetT(string strval) {
// ((Foo<t>)this).Set(strval);
// }
}
class Foo<T> : Foo {
private T val;
public void Set(string strval) {
if (this is Foo<float>) {
this.val = float.Parse(strval);
} else if (this is Foo<int>) {
this.val = int.Parse(strval);
}
}
}
Now I create an object and put it in an ArrayList:
ArrayList a = new ArrayList();
a.Append(new Foo<float>);
And then I forget the type of Foo<>. Now, how do I Set? I tried the obvious candidates:
(Foo)a[0].Set("5.0");
(Foo<a[0].GetType()>)a[0].Set("5.0");
but those failed.
Is there a way I can call that Set method without explicitly knowing the type of Foo<>?
If not, can I somehow save type of Foo into Foo.t, and then uncomment and use Foo.SetT?
Ah, generics. Very nice tool if you know how to use them :-)
Regards,
dijxtra
One way is to make your generic Foo class implement an interface:
interface IFoo {
void Set(string strval);
}
class Foo<T> : IFoo {
private T val;
public void Set(string strval) {
...
}
}
Then you can cast to IFoo and call Set():
((IFoo)a[0]).Set("5.0");
There's absolutely no reason to be using generics here. Generics are intended to be used when the type of operations you will be performing are generic. In other words, they are independent of the type(s) on which they are performed. You are doing the opposite: the operation will be different depending on the types.
Given that, you should remove the generic parameter, make Set() and Foo abstract, and derive appropriate classes to handle the different types:
abstract class Foo
{
public abstract void Set(string value);
}
class FooDouble : Foo
{
double val;
public override void Set(string value)
{
this.val = double.Parse(value);
}
}
// Etc.
Then, you should be storing your Foos in a List<T>:
List<Foo> fooList = new List<Foo>();
fooList.Add(new FooDouble());
Later, you can say this:
fooList[0].Set("5.0");
And it will just work! No need to remember!
You want to override the implementation of Set in the derived classes.
class Foo {
public virtual void Set(string val);
}
class Foo<T> : Foo {
public override void Set(string val);
}
In addition to what Jimmy pointed out for your base class, you could use a generic collection instead of an ArrayList and make use of a type converter:
public interface IFoo
{
void Set(string value);
}
public class Foo<T> : IFoo
{
private T val;
public void Set(string value)
{
var typeConverter = TypeDescriptor.GetConverter(typeof(T));
if(typeConverter.CanConvertFrom(typeof(string)))
{
val = (T)typeConverter.ConvertFromString(value);
}
else
{
throw new InvalidOperationException();
}
}
}
The above will work with either your ArrayList:
ArrayList a = new ArrayList();
a.Append(new Foo<float>());
((IFoo)a[0]).Set("123.4");
Or with a typed collection:
List<IFoo> list = new List<IFoo>();
list.Add(new Foo<float>());
list[0].Set("123.4");
As an added bonus, you don't need to have an if statement in your Set method and try to account for all possible types.
If you want to know the type parameter that was used in you generic, use the GetGenericArguments method.
class Foo<T> {
int input_as_int;
float input_as_float;
public void Set(string strval) {
if (this.GetType().GetGenericArguments().First() == typeof(float)) {
this.input_as_float = float.Parse(strval);
} else if (this.GetType().GetGenericArguments().First() == typeof(int)) {
this.input_as_int = int.Parse(strval);
}
// Else .. throw an exception? return default value? return 0? what makes sense to your application
}
or alternately if you could by pass the Interface entirely and pass the input string in the constructor.
public class Foo<T>
{
public Foo (string input)
{
var typeConverter = TypeDescriptor.GetConverter(typeof(T));
if (typeConverter.CanConvertFrom(typeof(string)))
{
Value = (T)typeConverter.ConvertFromString(input);
}
else
{
throw new InvalidOperationException();
}
}
public T Value { get; set;
}
}
then you can just use it like so.
var test = new List<int> Foo ("3");
using System;
using System.Collections;
using System.Collections.Generic;
class Foo {
}
class Foo<T> : Foo {
private T val;
public void Set(string strval) {
var _type = typeof(T);
val = (T)(_type.InvokeMember("Parse", System.Reflection.BindingFlags.InvokeMethod, null, null, new Object[] { strval }));
}
override public string ToString(){
return String.Format("{0}", val);
}
}
class Sample {
static void Main(string[] args){
ArrayList a = new ArrayList();
a.Add(new Foo<float>());
a.Add(new Foo<int>());
dynamic ax = a[0];
ax.Set("5.5");
ax = a[1];
ax.Set("55");
//EDIT
//But I may have to set the float value to Foo <int> If you forgot
// ((Foo<float>)a[0]).Set("5.5");
// ((Foo<int>)a[1]).Set("55");
Console.WriteLine("{0},{1}", a[0], a[1]);
}
}
How can I set generic type dynamically?
public class A
{
public int X { get; set; }
public A()
{
X = 9000;
}
}
public class Class1
{
public void Test()
{
List<A> theList = new List<A>() {
new A { X = 1 },
new A { X = 2 }
};
object testObj = theList;
var argType = testObj.GetType().GetGenericArguments()[0];
Foo(testObj as ICollection<argType>); // ?
}
public void Foo<T>(ICollection<T> items) where T:new()
{
T newItem = new T();
items.Add(newItem);
}
To do in "regular" c# you would use reflection to obtain the MethodInfo, then use MakeGenericMethod() and Invoke(). However, this is easier:
Foo((dynamic)testObj);
The reflection approach here is:
var method = typeof(Class1).GetMethod("Foo").MakeGenericMethod(argType);
method.Invoke(this, new object[] { testObj });
You can't do that, because in the Foo function you are supposed to do something with the collection, and there's no guarantee that the type will be safe.
The only way is using an "object" then casting to the proper type within the Fooo function.