I have a generic class:
public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new()
{
}
From that generic class, I would like to access a static function from the LinkedItem Class which is a descendant of MyItem class. (thus without creating an instance of the LinkedItem).
Is it possible?
Thank you,
Eric
Yes, it is possible, but you have to use reflection by obtaining a MethodInfo from typeof(T).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static) and then calling Invoke on it.
It can be very useful, particularly if using the same technique on a ConstructorInfo rather than a MethodInfo, to create a generic factory that uses parameters in the constructor. It is though one to use sparingly. In particular, there is no way of guaranteeing at compile time that the type in question has a static method of the required signature, so type-safety is gone and such an error won't be caught until run-time.
It can be done through reflection. There's no straight forward way to do it since C# has no API constraints on static memebers.
I am not sure what is the scenario you're in, but in most cases this is not a recommended solution :)
public class MyList<LinkedItem> : List<LinkedItem>
where LinkedItem : MyItem, new()
{
public int CallStaticMethod()
{
// Getting a static method named "M" from runtime type of LinkedItem
var methodInfo = typeof(LinkedItem)
.GetMethod("M", BindingFlags.Static | BindingFlags.Public);
// Invoking the static method, if the actual method will expect arguments
// they'll be passed in the array instead of empty array
return (int) methodInfo.Invoke(null, new object[0]);
}
}
public class MyItem
{
}
class MyItemImpl : MyItem
{
public MyItemImpl()
{
}
public static int M()
{
return 100;
}
}
So, for example the next code will print 100:
public void Test()
{
Console.WriteLine(new MyList<MyItemImpl>().CallStaticMethod());
}
No this is not possible directly from the type parameter because you cannot invoke static methods on generic type parameters (C# Lang Spec section 4.5).
A type parameter cannot be used in a member access (§7.5.4) or type name (§3.8) to identify a static member or a nested type.
Yes this is possible to achieve via reflection tricks as other people noted. But generally speaking using reflection to solve a simple method invocation scenario is an indication of bad design.
A much better design would be to pass a factory / delegate around which encapsulates the static method in a type safe manner.
class MyItem : MyItem {
static void TheFunction() { ... }
}
public class MyList<LinkedItem> : List<LinkedItem> where LinkedItem : MyItem, new()
{
public MyList(Action theStaticFunction) {
...
}
}
new MyList<MyItem>(MyItem.TheFunction);
This isn't possible. There's no way to declare a constraint on the LinkedItem parameter that says that it must contain the static method in question.
Possibly the closest you'll get is:
public class ILinkedItemFactory<T>
{
void YourMethodGoesHere();
}
public class MyList<LinkedItem, Factory> : List<LinkedItem>
where Factory : ILinkedItemFactory<LinkedItem>
where LinkedItem : MyItem, new()
{
public MyList(Factory factory)
{
factory.YourMethodGoesHere();
}
}
This is, by default, not possible. However, if you know the name of the method you want to invoke, and you are positive that every LinkedItem type will contain this method, you can use reflection to reach your goal. Note: there's often a better way than resolving to reflection for general programming tasks.
The following will always output true for DoSomething. It invokes a static member that's always available (I removed your generic type constraint, as that's not important with static methods).
public class MyList<LinkedItem> : List<LinkedItem>
{
public bool DoSomething()
{
Type t = typeof(LinkedItem);
object o = new Object();
var result = t.InvokeMember("ReferenceEquals",
BindingFlags.InvokeMethod |
BindingFlags.Public |
BindingFlags.Static,
null,
null, new[] { o, o });
return (result as bool?).Value;
}
}
// call it like this:
MyList<string> ml = new MyList<string>();
bool value = ml.DoSomething(); // true
PS: meanwhile, while I typed this, others seem to suggest the same approach ;-)
This is completely possible though not directly in the way you are stating without maybe reflection. You would want to implement a non-static access method in the baseclass and have it overridden in every specific inheriting class.
public class MyItem
{
public static void DoSomeStaticStuff() { //DoSomeStaticStuff for MyItem }
public virtual void AccessSomeStaticStuff() { MyItem.DoSomeStaticStuff(); }
}
public class SomeItem : MyItem
{
public static void DoSomeStaticStuff() { //DoSomeStaticStuff for SomeItem }
public override void AccessSomeStaticStuff() { SomeItem.DoSomeStaticStuff(); }
}
Then in your class which has the constraint where T : MyItem you would just call T.AccessSomeStaticStuff();
Related
i have two classes: Class1 and Class2
class Class1
{
public void method();
}
class Class2
{
public void method();
}
in another place I have the class type and I want to create an instance from it.
type is typeof(Class1) or typeof(Class2)
public void CreateInstance(Type type)
{
var instance = Activator.GetInstance(type);
instance.method(); //compile error: object doesn't contain method
}
a solution is I define an interface that my classes implement that interface.
interface IInterface
{
void method();
}
public void CreateInstance(Type type)
{
var instance = Activator.GetInstance(type);
((IInterface)instance).method();
}
because I can't access to class definition I can't do this. How can I do this?
This is what you need:
public void CreateInstance(Type type)
{
var instance = Activator.CreateInstance(type);
type.GetMethod("method").Invoke(instance, null);
}
Or, alternatively, use dynamic:
public void CreateInstance(Type type)
{
dynamic instance = Activator.CreateInstance(type);
instance.method();
}
NB: You had GetInstance instead of CreateInstance in your code, but I corrected it.
You can avoid reflection and performance issues entirely by using a generic method and dynamic:
public void CreateInstance<T>() where T:new()
{
dynamic instance=new T();
instance.method();
}
Which you can call simply by passing the type:
CreateInstance<Class1>();
CreateInstance<Class2>();
Type safety is lost either when using reflection or using dynamic. Checking for the existence of a method with reflection isn't any safer or less risky than having the runtime throw an exception - in both cases you have to handle an exceptional condition. What are you going to do when this exception occurs?
With dynamic, a missing method will raise a RuntimeBinderException specifying that a method is missing. If I changed the method call from method to method1 I'll get an exception saying:
'ConsoleApplication24.Class1' does not contain a definition for 'method1'
This way the code does not pay the reflection penalty for the normal cases. This is also safer - there is no way that the exception can be missed.
The only way that provides compile-type safety is to have the classes implement an interface and use it as a generic constraint, eg:
public static void CreateInstance<T>() where T : ISomething, new()
{
var instance = new T();
instance.method();
}
Best option would be to use interface for safety. But if you can't do that, you can invoke this method through reflection:
public class MyClass
{
public void Method()
{
Console.WriteLine("executed");
}
}
public class MyActivator
{
public static void CreateInstance(Type type)
{
var instance = Activator.CreateInstance(type);
var method = GetMethod("method");
method.Invoke(instance, null);
}
}
And then you call this by:
MyActivator.CreateInstance(typeof(MyClass));
Remember to add some checking if method is not null
I have the following class:
public class GenericClass<T> : IGenericClass<T> where T : class
{
public GenericClass()
public GenericClass(Entity e)
public IQueryable<T> GenericMethod1()
public IEnumerable<T> GenericMethod2()
public T NonGenericMethod1(T t)
}
The class works great; however I'm starting to run into issues where I have to instantiate another instance of GenericClass for every type T I want to use, and it's getting a little crazy. Is there some sort of abstraction I can create to simplify this?
I was heading in this direction, but I can't tell if this is the right choice or if there is a better design pattern I could use; plus, the two invoke calls are not working correctlly at all.
public class TestClass
{
private Type type;
public object Invoke(string method, object obj)
{
type = obj.GetType();
MethodInfo m = typeof(GenericClass<>).GetMethod(method);
var result = new object();
if(m.IsGenericMethod == true)
result = m.MakeGenericMethod(type).Invoke(null, new object[] { obj });
else
result = m.Invoke(null, new object[] { obj });
return result;
}
}
TIA
however I'm starting to run into issues where I have to instantiate another instance of GenericClass for every type T I want to use, and it's getting a little crazy
It's hard to guess without some implementation of GenericClass... but I see constructors and methods - no properties (and no fields?).
If that's the case, you may want to make GenericClass a static class with static methods. Then you aren't allowed to instantiate it and you can call the methods directly from the type:
public static class GenericClass
{
public static IQueryable<T> GenericMethod1<T>() where T:class
public static IEnumerable<T> GenericMethod2<T>() where T:class
public static object NonGenericMethod1(object t)
}
Called by
IQueryable<Customer> query = GenericClass.GenericMethod1<Customer>();
IEnumerable<Customer> items = GenericClass.GenericMethod2<Customer>();
Customer c = (Customer) GenericClass.NonGenericMethod1(customerInstance);
Or perhaps there are properties or fields, but they aren't dependent on T, then you can move the Generic responsibility to the methods instead of the class.
Now you can have an instance, and that instance can handle all of the T's you want to throw at it.
public class GenericClass : IGenericClass
{
public IQueryable<T> GenericMethod1<T>() where T:class
public IEnumerable<T> GenericMethod2<T>() where T:class
public object NonGenericMethod1(object t)
}
I apologize for the generic-ness of this answer, however that is due to the generic-ness of the question.
I don't think this approach will work. The main issue is that you are trying to create the generic method based on the type in order to avoid instantiating an instance of the appropriate GenericClass<T>. But the reason your Invokes are failing is that you are passing in null as the target object, even though they are instance methods. The way to get them to work is to construct an instance of the appropriate GenericClass<T>, but of course this is what you want to avoid.
If you wanted to go this reflaction route (so you'd still have the centralized construction location,) you can do this via reflection with the following code:
Type specificType = typeof(GenericClass<>).MakeGenericType(new Type[] { type });
var specificInstance = Activator.CreateInstance(specificType);
You can then pass in specificInstance as the first parameter to Invoke().
Is it not supported, is it supported but I have to do some tricks?
Example:
class Foo
{
public Foo<T1,T2>(Func<T1,T2> f1,Func<T2,T1> f2)
{
...
}
}
the generics are only used in constructor, there is no field/property depended on them, I use it (generics) to enforce the type correlation for f1 and f2.
Remark: I found the workaround -- static method Create, but anyway I am curious why I have problem with straightforward approach.
No, generic constructors aren't supported in either generic or non-generic classes. Likewise generic events, properties and finalizers aren't supported.
Just occasionally I agree it would be handy - but the syntax would look pretty awful. For example, suppose you had:
public class Foo<T> {}
public class Foo
{
public Foo<T>() {}
}
What would
new Foo<string>()
do? Call the generic constructor of the non-generic class, or the normal constructor of the generic class? You'd have to differentiate between them somehow, and it would be messy :(
Likewise, consider a generic constructor in a generic class:
public class Foo<TClass>
{
public Foo<TConstructor>() {}
}
How would you call the constructor? Hopefully we can all agree that:
new Foo<string><int>()
is pretty hideous...
So yes, semantically it would be occasionally useful - but the resulting ugliness counterbalances that, unfortunately.
Generic constructors are not supported, but you can get around this by simply defining a generic, static method that returns a new Foo:
class Foo
{
public static Foo CreateFromFuncs<T1,T2>(Func<T1,T2> f1,Func<T2,T1> f2)
{
...
}
}
which is used like this:
// create generic dependencies
var func1 = new Func<byte, string>(...);
var func2 = new Func<string, byte>(...);
// create nongeneric Foo from dependencies
Foo myFoo = Foo.CreateFromFuncs<byte, string>(func1, func2);
Here is an practical example about how you would like to have extra constructor type parameter, and the workaround.
I am going to introduce a simple RefCounted wrapper for IDisposable:
public class RefCounted<T> where T : IDisposable
{
public RefCounted(T value)
{
innerValue = value;
refCount = 1;
}
public void AddRef()
{
Interlocked.Increment(ref refCount);
}
public void Dispose()
{
if(InterlockedDecrement(ref refCount)<=0)
innerValue.Dispose();
}
private int refCount;
private readonly innerValue;
}
This seems to be fine. But sooner or later you would like to cast a RefCounted<Control> to RefCounted<Button> whilst keep both object reference counting, i.e. only when both instances being disposed to dispose the underlying object.
The best way is if you could write (like C++ people can do)
public RefCounted(RefCounted<U> other)
{
...whatever...
}
But C# does not allow this. So the solution is use some indirection.
private readonly Func<T> valueProvider;
private readonly Action disposer;
private RefCounted(Func<T> value_provider, Action disposer)
{
this.valueProvider = value_provider;
this.disposer = disposer;
}
public RefCounted(T value) : this(() => value, value.Dispose)
{
}
public RefCounted<U> Cast<U>() where U : T
{
AddRef();
return new RefCounted<U>(() => (U)(valueProvider()),this.Dispose);
}
public void Dispose(){
if(InterlockedDecrement(ref refCount)<=0)
disposer();
}
If your class have any fields that are of generic type, you have no choice but to put all those types to the class. However, if you just wanted to hide some type from the constructor, you will need to use the above trick - having a hidden constructor to put everything together, and define a normal generic function to call that constructor.
Is there any way to do code such this:
class GenericClass<T>
{
void functionA()
{
T.A();
}
}
Or, how to call a function of type parameter (type is some my custom class).
Re:
T.A();
You can't call static methods of the type-parameter, if that is what you mean. You would do better to refactor that as an instance method of T, perhaps with a generic constraint (where T : SomeTypeOrInterface, with SomeTypeOrInterface defining A()). Another alternative is dynamic, which allows duck-typing of instance methods (via signature).
If you mean that the T is only known at runtime (as a Type), then you would need:
typeof(GenericClass<>).MakeGenericType(type).GetMethod(...).Invoke(...);
To call a method of a generic type object you have to instantiate it first.
public static void RunSnippet()
{
var c = new GenericClass<SomeType>();
}
public class GenericClass<T> where T : SomeType, new()
{
public GenericClass(){
(new T()).functionA();
}
}
public class SomeType
{
public void functionA()
{
//do something here
Console.WriteLine("I wrote this");
}
}
I think you are looking for generic type constraints:
class GenericClass<T> where T : MyBaseClass
{
void functionA<T>(T something)
{
something.A();
}
}
In terms of the code you posted - in order to call something on T, you will need to pass it as a parameter to functionA. The constraint you use will have to ensure that any T has an A method that can be used.
I understand from your code that you want to call a type parameter static method, and that's just impossible.
See here for more info : Calling a static method on a generic type parameter
I've got an abstract class like this;
public abstract PropertyBase
{
public static System.Type GetMyType()
{
return !!!SOME MAGIC HERE!!!
}
}
I'd like to subclass it, and when I call the static GetMyType(), I'd like to return the subclass's type. So if I declare a subtype;
public class ConcreteProperty: PropertyBase {}
then when I call
var typeName = ConcreteProperty.GetMyType().Name;
I expect 'typeName' to be set to "ConcreteProperty." I suspect there's no way to do it, but I'm interested if anyone out there knows a way to get this info.
(The particular problem I'm trying to solve is the verbosity of dependency properties in WPF; I'd love to be able to do something like this;
class NamedObject : DependencyObject
{
// declare a name property as a type, not an instance.
private class NameProperty : PropertyBase<string, NamedObject> { }
// call static methods on the class to read the property
public string Name
{
get { return NameProperty.Get(this); }
set { NameProperty.Set(this, value); }
}
}
And I almost have an implementation, but I can't quite get the info I need out of my NameProperty class.)
You can partially achieve (1-level of inheritance deep) using generics:
class PropertyBase<T>
{
public static Type GetMyType() { return typeof (T); }
}
// the base class is actually a generic specialized by the derived class type
class ConcreteProperty : PropertyBase<ConcreteProperty> { /* more code here */ }
// t == typeof(ConcreteProperty)
var t = ConcreteProperty.GetMyType();
The subclassing bit will not work, because a static method is tied to a type. It is a method of a type, not a method of an instance. The subtype does not contain the static methods of a base type, because they are different types and the static method is tied to the base type. Even though the compiler might allow you to call a static method of a base class as through a derived class, it will in reality call the method from the base class. It's just syntax sugar. For the same reason you cannot "override" static methods in subclasses because it would make little sense.
Just wondering why would need to do something like this?
var typeName = ConcreteProperty.GetMyType().Name;
Anyhow you know the type while calling the method, you can simply do this as well..
var typeName = typeof(ConcreteProperty).Name;
Just in case you need to do this, you can use "shadowing" to override the implementation of base class in child class.
public class ConcreteProperty : PropertyBase {
public new static Type GetMyType {
//provide a new implementation here
}
}