Generic Method - Can I avoid using reflection in this code? - c#

Say I have the following method:
private static void SetLastModifiedTimeUser<TEntity>(TEntity entity) where TEntity : class
{
PropertyInfo propertyInfo;
propertyInfo = entity.GetType().GetProperty("LastModifiedUser");
if (propertyInfo != null)
propertyInfo.SetValue(entity, IdentityHelper.UserName, null);
}
As you can see, the method accepts a generic type. Every class passed to this method will contain a property named 'LastModifiedUser'. Is there a way I can access this property without using reflection? I don't think there is, but I thought I'd ask.

Yes, if all your entities have LastModifiedUser property, then you can make all entities inherit from base class, or implement some interface like
public interface IModifyable
{
string LastModifiedUser { get; set; }
}
Then just add this constraint (or make your method non-generic, accepting IModifyable)
where TEntity : class, IModifyable
And your code will look like:
private static void SetLastModifiedTimeUser<TEntity>(TEntity entity)
where TEntity : class, IModifyable
{
entity.LastModifiedUser = IdentityHelper.UserName;
}

Have your class inherit from an interface that defines a LastModifiedUser property.
public interface ILastModifiedUser
{
public string LastModifiedUser { get; set; }
}
Change your method declaration to
private static void SetLastModifiedTimeUser(ILastModifiedUser entity)

If you can't modify all the classes to implement a common interface you can use dynamic
private static void SetLastModifiedTimeUser<TEntity>(TEntity entity) where TEntity : class
{
dynamic d = entity;
d.LastModifiedUser = IdentityHelper.UserName;
}
Otherwise it is as simple as shown by Robert Harvey.

If you can't add an interface to your objects, consider this approach.
The first time it encounters each Type (TEntity), it looks up the property and gets the property's SetMethod. Then, on each use, it creates invokes the method.
var one = new EntityOne();
LastModifiedTimeUserSetter.Set(one);
Console.WriteLine(one.LastModifiedUser);
public static class LastModifiedTimeUserSetter
{
public static void Set<TEntity>(TEntity entity)
{
var method = Properties.GetOrAdd(typeof (TEntity), GetSetMethod);
var action = (Action<string>) Delegate.CreateDelegate(typeof (Action<string>), entity, method);
action(IdentityHelper.UserName);
}
static MethodInfo GetSetMethod(Type type)
{
var prop = type.GetProperty("LastModifiedUser");
if (prop == null)
return null;
return prop.GetSetMethod();
}
static readonly ConcurrentDictionary<Type, MethodInfo> Properties = new ConcurrentDictionary<Type, MethodInfo>();
}
Going further
There is a way to further improve performance by using the System.Reflection.Emit.MethodBuilder. And building a method that takes Entity and sets the property.
public static class LastModifiedTimeUserSetter
{
public static void Set<TEntity>(TEntity entity)
{
var action = (Action<TEntity>) Properties.GetOrAdd(typeof(TEntity), CreateDynamicSetMethodDelegate);
if(action != null)
action(entity);
}
static Delegate CreateDynamicSetMethodDelegate(Type type)
{
return CreateDynamicSetMethod(type).CreateDelegate(GetActionType(type));
}
static DynamicMethod CreateDynamicSetMethod(Type typeWithProperty)
{
var methodBuilder = new DynamicMethod(
"Dynamic_" + typeWithProperty.FullName + "_SetLastModifiedUser",
typeof (void),
new[] {typeWithProperty});
EmitSimpleAssignmentMethod(methodBuilder,
GetIdentityHelperUserNameGetMethod(),
GetPropertySetMethod(typeWithProperty));
return methodBuilder;
}
static MethodInfo GetIdentityHelperUserNameGetMethod()
{
return typeof(IdentityHelper).GetProperty("UserName").GetGetMethod();
}
static MethodInfo GetPropertySetMethod(Type type)
{
var prop = type.GetProperty("LastModifiedUser");
if (prop == null)
return null;
return prop.GetSetMethod();
}
static void EmitSimpleAssignmentMethod(DynamicMethod methodBuilder, MethodInfo getMethod, MethodInfo setMethod)
{
var il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, getMethod, null);
il.EmitCall(OpCodes.Call, setMethod, null);
il.Emit(OpCodes.Ret);
}
static Type GetActionType(Type type)
{
return typeof (Action<string>).GetGenericTypeDefinition().MakeGenericType(type);
}
static readonly ConcurrentDictionary<Type, Delegate> Properties = new ConcurrentDictionary<Type, Delegate>();
}
See an Article from MSDN magazine about XBOX Live.

Related

Proper run-time construction pattern for large number of objects

What is the best way to create derived objects at run-time while adhering to LSP and always keeping the objects in a valid state.
I'm fairly new to construction patterns such as Factory and Builder and most of the examples I find are very simplistic. Here is my scenario:
I have one base class (some things left out for brevity):
public abstract BaseClass
{
public string Property1 { get; set ... null guard; }
public string Property2 { get; set ... conditional null guard; }
public virtual bool RequiresProperty2 => false;
protected BaseClass(string property1)
{
null guard
Property1 = property1;
}
}
I have 50+ derived classes. Some of which require prop2 some of which don't. The ones that require prop2 have a constructor that forces prop2 to be passed in, enforcing that all BaseClass derived objects are in a valid state upon construction. I'm also trying to adhere to LSP and I'm using Castle Windsor for dependency injection.
The solution I've come up with is to create a factory that returns a builder:
public interface IFactory
{
IBuilder Create(string type);
}
public interface IBuilder
{
IBuilder SetProperty1(string property);
IBuilder SetProperty2(string property);
BaseClass Build();
}
The concrete implementation of the factory loads all the types that inherit from BaseClass through reflection. When you call Factory.Create(...) you pass it a string which is the string name of the type you want to create. Then the factory creates a builder passing the appropriate Type to the builder's constructor. The builder looks like so:
public sealed class ConcreteBuilder : IBuilder
{
private static Type ClassType = typeof(BaseClass);
private static readonly ConcurrentDictionary<Type, Delegate>
ClassConstructors = new ConcurrentDictionary<Type, Delegate>();
private readonly Type type;
private string property1;
private string property2;
public ConcreteBuilder(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
if (!type.IsSubclassOf(ClassType))
{
throw new ArgumentException("Must derive from BaseClass.");
}
this.type = type;
}
public IBuilder SetProperty1(string property)
{
this.property1 = property;
return this;
}
public IBuilder SetProperty2(string property)
{
this.property2 = property;
return this;
}
public BaseClass Build()
{
var arguments = BuildArguments();
Delegate ctor;
if (ClassConstructors.TryGetValue(this.type, out ctor))
{
return (BaseClass)ctor.DynamicInvoke(arguments);
}
return (BaseClass)GetConstructor(arguments).DynamicInvoke(arguments);
}
private object[] BuildArguments()
{
var args = new List<object>();
if (!string.IsNullOrEmpty(this.property1))
{
args.Add(this.property1);
}
if (!string.IsNullOrEmpty(this.property2))
{
args.Add(this.property2);
}
return args.ToArray();
}
private Delegate GetConstructor(object[] arguments)
{
var constructors = this.type.GetConstructors();
foreach (var constructor in constructors)
{
var parameters = constructor.GetParameters();
var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
if (parameterTypes.Length != arguments.Length + 1) continue;
if (!parameterTypes.Zip(arguments, TestArgumentForParameter).All(x => x))
{
continue;
}
var parameterExpressions = parameters.Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray();
var callConstructor = Expression.New(constructor, parameterExpressions);
var ctor = Expression.Lambda(callConstructor, parameterExpressions).Compile();
ClassConstructors.TryAdd(this.type, ctor);
return ctor;
}
throw new MissingMethodException("No constructor found");
}
private static bool TestArgumentForParameter(Type parameterType, object argument)
{
return (argument == null && !parameterType.IsValueType) || (parameterType.IsInstanceOfType(argument));
}
}
Is there a better way to do this? Am I going about this the right way? I know DynamicInvoke is slow. Should I be going about this differently?

Accessing attributes on fields using extension method

I want to check custom attributes on my class members (fields only) by using an extension method.
public class DatabaseIdAttribute : Attribute
{
public int ID { get; set; }
public DatabaseIdAttribute(int id)
{
this.ID = id;
}
}
public class MyClass
{
[DatabaseId(1)]
double Height {get;set;}
[DatabaseId(2)]
double Width {get;set;}
double Area { get { return this.Height * this.Width; }
}
I want to use LINQ expression in the extension method to access the class field instead of passing magic strings.
var myClass = new MyClass();
var attribute = myClass.GetAttribute<DatabaseIdAttribute>(c => c.Height);
Is it possible to achieve?
[EDIT]
For the time being, I have achieved the following with the help of #leppie
public static MemberInfo GetMember<T, R>(this T instance, Expression<Func<T, R>> selector)
{
var member = selector.Body as MemberExpression;
if (member != null)
{
return member.Member;
}
return null;
}
public static T GetAttribute<T>(this MemberInfo member) where T : Attribute
{
return member.GetCustomAttributes(false).OfType<T>().SingleOrDefault();
}
which enables to get the attribute in the following way
var c = new MyClass();
var attribute = c.GetMember(m => m.Height).GetAttribute<DatabaseIdAttribute>();
but I want to be able to access it in the following way
var c = new MyClass();
var attribute = c.GetAttribute<DatabaseIdAttribute>(m => m.Height);
You are almost there! This should work (untested).
public static class ObjectExtensions
{
public static MemberInfo GetMember<T,R>(this T instance,
Expression<Func<T, R>> selector)
{
var member = selector.Body as MemberExpression;
if (member != null)
{
return member.Member;
}
return null;
}
// unnecessary in .NET 4.5 and up, see note!
public static T GetAttribute<T>(this MemberInfo meminfo) where T : Attribute
{
return meminfo.GetCustomAttributes(typeof(T)).FirstOrDefault() as T;
}
}
Usage:
var attr = someobject.GetMember(x => x.Height).
GetAttribute<DatabaseIdAttribute>();
Note: As of .NET 4.5 and up (including .NET Core), the BCL provides a GetCustomAttribute<T>(MemberInfo) extension method that functions identically to the GetAttribute method defined above, and should be used instead if available.
If you don't mind supplying the extra generic types, you can do this:
public static class ReflectionHelper
{
public static TAttr GetAttribute<TClass, TProp, TAttr>(Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
{
var member = selector.Body as MemberExpression;
return member.Member.GetCustomAttributes<TAttr>(false).First();
}
}
Then you can use it like this:
var attribute = ReflectionHelper.GetAttribute<MyClass, double, DatabaseIdAttribute>(m => m.Height);
Note that this is not an extension method (as we can't have static extensions) so there is no need to create an instance of your class.
Of course you could still have the extension method version:
public static TAttr GetAttribute<TClass, TProp, TAttr>(this TClass instance, Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
{
var member = selector.Body as MemberExpression;
return member.Member.GetCustomAttributes<TAttr>(false).First();
}
Which would let you call it like so:
var c = new MyClass();
var attribute = c.GetAttribute<MyClass, double, DatabaseIdAttribute>(m => m.Height);
But either way is quite verbose. If you want the compile to infer all of the generic types, we'd need to pass in an instance of our attribute:
public static class ReflectionHelper
{
public static TAttr GetAttribute<TClass, TProp, TAttr>(TAttr attribute, Expression<Func<TClass, TProp>> selector) where TAttr : Attribute
{
var member = selector.Body as MemberExpression;
return member.Member.GetCustomAttributes<TAttr>(false).First();
}
}
Usage:
var attribute = ReflectionHelper.GetAttribute(new DatabaseIdAttribute(), m => m.Height);

C#: Holding a collection of handler objects and finding the right one

So I have an interface called IWorkItem that is implemented in WorkA, WorkB and many other classes.
public interface IWorker<T> where T : IWorkItem
{
void Process(T item);
}
The IWorker<T> interface is implemented in WorkerA (IWorker<WorkA>), WorkerB (IWorker<WorkB>) and many other classes.
public static void ProcessWorkItem(IWorkItem item)
{
(/* find the right worker */).Process(item);
}
Now my problem is: How do find a worker object that is able to process the given IWorkItem?
My first attempts look like this, but the generic type arguments are a problem:
public static class WorkerRepository
{
private static Dictionary<Type, IWorker<???>> RegisteredWorkers =
new Dictionary<Type, IWorker<???>>();
public static void RegisterWorker(IWorker<???> worker)
{
var handled = from iface in worker.GetType().GetInterfaces()
where iface.IsGenericType
where iface.GetGenericTypeDefinition() == typeof(IWorker<>)
select iface.GetGenericArguments()[0];
foreach (var type in handled)
if (!RegisteredWorkers.ContainsKey(type))
RegisteredWorkers[type] = worker;
}
public static void ProcessWorkItem(IWorkItem item)
{
RegisteredWorkers[item.getType()].Process(item);
}
}
So I have the Dictionary that contains the workers. Which type argument do I need here? In Java I could just use ? extends IWorkItem, but do I do that in C#?
Then there is RegisterWorker. You would probably suggest a generic type argument for the entire method, like RegisterWorker<T>(IWorker<T> worker). However, that also won't work, since I would like to dynamically load, instantiate and register Workers.
Is this even the right approach or is there a better way to accomplish this?
I made a few changes but got a solution where you can keep things generic (instead of using objects). Not sure if you even care, but thought to add it as answer and let you decide.
I also wrote a test to check if it actually works, you should be able to copy/paste it.
[TestFixture]
public class WorkerThing
{
[Test]
public void RegisterAndRetrieveWorkers()
{
var repo = new WorkerRepository();
repo.RegisterWorker(new WorkerA());
var workerA = repo.RetrieveWorkerForWorkItem(new WorkItemA());
Assert.IsTrue(workerA is WorkerA);
repo.RegisterWorker(new WorkerB());
var workerB = repo.RetrieveWorkerForWorkItem(new WorkItemB());
Assert.IsTrue(workerB is WorkerB);
}
}
The WorkerRepository class.
public class WorkerRepository
{
private readonly Dictionary<Type, IWorker<IWorkItem>> _registeredWorkers =
new Dictionary<Type, IWorker<IWorkItem>>();
public void RegisterWorker(IWorker<IWorkItem> worker)
{
var type = (from iface in worker.GetType().GetInterfaces()
where iface.IsGenericType
where iface.GetGenericTypeDefinition() == typeof(IWorker<>)
select iface.GetGenericArguments()[0]).First();
if (!_registeredWorkers.ContainsKey(type))
{
_registeredWorkers[type] = worker;
}
}
// You don't need this method, just added it to check if I indeed retrieved the correct type
//
public IWorker<IWorkItem> RetrieveWorkerForWorkItem(IWorkItem item)
{
var type = item.GetType();
var registeredWorker = _registeredWorkers[type];
return registeredWorker;
}
public void ProcessWorkItem(IWorkItem item)
{
var type = item.GetType();
var registeredWorker = _registeredWorkers[type];
registeredWorker.Process(item);
}
}
The work item interfaces & classes.
public interface IWorkItem
{
}
public class WorkItemA : IWorkItem
{
}
public class WorkItemB : IWorkItem
{
}
And here I added the out keyword to allow covariance typing on the interface. That way you can convert WorkerA to IWorker<IWorkItem>. (as in the unit test example)
public interface IWorker<out T> where T : IWorkItem
{
void Process(IWorkItem workItem);
}
public class WorkerA : IWorker<WorkItemA>
{
public void Process(IWorkItem item)
{
}
}
public class WorkerB : IWorker<WorkItemB>
{
public void Process(IWorkItem item)
{
}
}
No object dictionaries. No reflection. I hope the example is useful!
Cheers (and thx for the cool question, it kept me busy for a while :))
It looks like you want something like this:
private static Dictionary<Type, object> RegisteredWorkers = new Dictionary<Type, object>();
public static void RegisterWorker(object worker)
{
var handled = from iface in worker.GetType().GetInterfaces()
where iface.IsGenericType
where iface.GetGenericTypeDefinition() == typeof(Worker<>)
select iface.GetGenericArguments()[0];
foreach (var type in handled)
if (!RegisteredWorkers.ContainsKey(type))
RegisteredWorkers[type] = worker;
}
public static void ProcessWorkItem(WorkItem item)
{
object handler = RegisteredWorkers[item.getType()];
Type workerType = typeof(Worker<>).MakeGenericType(item.GetType());
MethodInfo processMethod = workerType.GetMethod("Process");
processMethod.Invoke(handler, new object[] { item });
}
If you don't want to invoke the handlers through reflection each time you can generate an Action<IWorkItem> handler when you register the handler:
public void RegisterHandler(object handler)
{
var handled = from iface in handler.GetType().GetInterfaces()
where iface.IsGenericType
where iface.GetGenericTypeDefinition() == typeof(IWorker<>)
select iface.GetGenericArguments()[0];
foreach (var type in handled)
{
if (!RegisteredWorkers.ContainsKey(type))
{
Action<IWorkItem> handleAction = HandlerAction(type, handler);
RegisteredWorkers[type] = handleAction;
}
}
}
public void Process(IWorkItem item)
{
Action<IWorkItem> handleAction = RegisteredWorkers[item.GetType()];
handleAction(item);
}
private static Action<IWorkItem> HandlerAction(Type itemType, object handler)
{
var paramExpr = Expression.Parameter(typeof(IWorkItem));
var castExpr = Expression.Convert(paramExpr, itemType);
MethodInfo processMethod = typeof(IWorker<>).MakeGenericType(itemType).GetMethod("Process");
var invokeExpr = Expression.Call(Expression.Constant(handler), processMethod, castExpr);
var lambda = Expression.Lambda<Action<IWorkItem>>(invokeExpr, paramExpr);
return lambda.Compile();
}

Map database column to constant value without the need for a property in the entity class

Is it possible to map a database column to a constant value without the need for a property in the entity class? This basically is a workaround for a missing default value on that column in the database in combination with a NOT NULL constrained. The database is external and can't be changed but I don't need all of the columns in that table and thus don't want to have corresponding properties in my entity class.
I am asking basically the same as described in this Hibernate JIRA issue.
Based on Firos answer I solved the problem. However, I didn't quite like the syntax to be used and the fact that I would have to create a new class for the default values for each entity.
The syntax I got now looks like this:
mapping.ConstantValue(0).Column(#"client_id");
// or
mapping.ConstantValue(0, #"client_id");
I created the following extension methods for it:
public static PropertyPart
ConstantValue<TType, TValue>(this ClasslikeMapBase<TType> map, TValue value)
{
var getter =
new ConstantValueGetter<TValue>(CreateUniqueMemberName(), value);
ConstantValueAccessor.RegisterGetter(typeof(TType), getter);
var propertyInfo =
new GetterSetterPropertyInfo(typeof(TType), typeof(TValue),
getter.PropertyName, getter.Method, null);
var parameter = Expression.Parameter(typeof(TType), "x");
Expression body = Expression.Property(parameter, propertyInfo);
body = Expression.Convert(body, , typeof(object));
var lambda = Expression.Lambda<Func<TType, object>>(body, parameter);
return map.Map(lambda).Access.Using<ConstantValueAccessor>();
}
public static PropertyPart
ConstantValue<TType, TValue>(this ClasslikeMapBase<TType> map,
TValue value, string column)
{
return map.ConstantValue(value).Column(column);
}
The important differences are:
The first of those extension methods returns a PropertyPart and has to be used in conjunction with the Column method to specify which column the constant value should be mapped to. Because of this, the column name is not known when the extension method is executed and we need to create one ourselves. This is done by CreateUniqueMemberName:
private static string CreateUniqueMemberName()
{
return "Dummy" + Guid.NewGuid().ToString("N");
}
Because you can only specify a type as access strategy and not an instance, I couldn't create an IPropertyAccessor implementation allowed me to simply pass an IGetter instance in the constructor. That's what ConstantValueAccessor.RegisterGetter(typeof(TType), getter); solves. ConstantValueAccessor has a static collection of getters:
internal class ConstantValueAccessor : IPropertyAccessor
{
private static readonly
ConcurrentDictionary<Type, SynchronizedCollection<IGetter>> _getters =
new ConcurrentDictionary<Type, SynchronizedCollection<IGetter>>();
public static void RegisterGetter(Type type, IGetter getter)
{
var getters =
_getters.GetOrAdd(type,
t => new SynchronizedCollection<IGetter>());
getters.Add(getter);
}
public IGetter GetGetter(Type theClass, string propertyName)
{
SynchronizedCollection<IGetter> getters;
if (!_getters.TryGetValue(theClass, out getters))
return null;
return getters.SingleOrDefault(x => x.PropertyName == propertyName);
}
// ...
}
The implementation of ConstantValueGetter<T> is the same as the one from the provided link.
Because it wasn't that much fun to implement GetterSetterPropertyInfo, here it is. One important difference is, that this implementation doesn't have any dependencies on (Fluent) NHibernate.
My implementation takes the same idea as hival but goes a lot further. the basis is an implementation of IPropertyAccessor
/// <summary>
/// Defaultvalues für nicht (mehr) benötigte Spalten siehe
/// http://elegantcode.com/2009/07/13/using-nhibernate-for-legacy-databases/
/// </summary>
public abstract class DefaultValuesBase : IPropertyAccessor
{
public abstract IEnumerable<IGetter> DefaultValueGetters { get; }
public bool CanAccessThroughReflectionOptimizer
{
get { return false; }
}
public IGetter GetGetter(Type theClass, string propertyName)
{
return DefaultValueGetters.SingleOrDefault(getter => getter.PropertyName == propertyName);
}
public ISetter GetSetter(Type theClass, string propertyName)
{
return new NoopSetter();
}
}
// taken from the link
[Serializable]
public class DefaultValueGetter<T> : IGetter {...}
// ---- and the most tricky part ----
public static void DefaultValues<T>(this ClasslikeMapBase<T> map, DefaultValuesBase defaults)
{
DefaultValuesInternal<T>(map.Map, defaults);
}
public static void DefaultValues<T>(this CompositeElementPart<T> map, DefaultValuesBase defaults)
{
DefaultValuesInternal<T>(map.Map, defaults);
}
private static void DefaultValuesInternal<T>(
Func<Expression<Func<T, object>>, PropertyPart> mapFunction, DefaultValuesBase defaults)
{
var noopSetter = new NoopSetter();
var defaultsType = defaults.GetType();
foreach (var defaultgetter in defaults.DefaultValueGetters)
{
var parameter = Expression.Parameter(typeof(T), "x");
Expression body = Expression.Property(parameter,
new GetterSetterPropertyInfo(typeof(T), defaultgetter, noopSetter));
body = Expression.Convert(body, typeof(object));
var lambda = Expression.Lambda<Func<T, object>>(body, parameter);
mapFunction(lambda).Column(defaultgetter.PropertyName).Access.Using(defaultsType);
}
}
// GetterSetterPropertyInfo inherits PropertyInfo with important part
public override string Name
{
get { return m_getter.PropertyName; } // propertyName is the column in db
}
// and finally in SomeEntityMap
this.DefaultValues(new SomeEntityDefaults());
public class SomeEntityDefaults : DefaultValuesBase
{
public override IEnumerable<IGetter> DefaultValueGetters
{
get
{
return new [] {
new DefaultValueGetter<int>("someColumn", 1),
new DefaultValueGetter<string>("somestrColumn", "empty"),
};
}
}
}
If you don't want to introduce property in your entity class the only solution I see is to create custom property accessor which will always return constant value. Here is possible implementation:
public class ConstantAccessor : IPropertyAccessor
{
#region IPropertyAccessor Members
public IGetter GetGetter(Type theClass, string propertyName)
{
return new ConstantGetter();
}
public ISetter GetSetter(Type theClass, string propertyName)
{
return new NoopSetter();
}
public bool CanAccessThroughReflectionOptimizer
{
get { return false; }
}
#endregion
[Serializable]
private class ConstantGetter : IGetter
{
#region IGetter Members
public object Get(object target)
{
return 0; // Always return constant value
}
public Type ReturnType
{
get { return typeof(object); }
}
public string PropertyName
{
get { return null; }
}
public MethodInfo Method
{
get { return null; }
}
public object GetForInsert(object owner, IDictionary mergeMap,
ISessionImplementor session)
{
return null;
}
#endregion
}
[Serializable]
private class NoopSetter : ISetter
{
#region ISetter Members
public void Set(object target, object value)
{
}
public string PropertyName
{
get { return null; }
}
public MethodInfo Method
{
get { return null; }
}
#endregion
}
}
Here how to use it:
<property name="Value"
access="ConsoleApplication2.ConstantAccessor, ConsoleApplication2"
column="a_value" type="int" />
Property "Value" doesn't need to exist in your entity. It is here because attribute "name" is required.

Calling a static method using a Type

How do I call a static method from a Type, assuming I know the value of the Type variable and the name of the static method?
public class FooClass {
public static FooMethod() {
//do something
}
}
public class BarClass {
public void BarMethod(Type t) {
FooClass.FooMethod() //works fine
if (t is FooClass) {
t.FooMethod(); //should call FooClass.FooMethod(); compile error
}
}
}
So, given a Type t, the objective is to call FooMethod() on the class that is of Type t. Basically I need to reverse the typeof() operator.
You need to call MethodInfo.Invoke method:
public class BarClass {
public void BarMethod(Type t) {
FooClass.FooMethod(); //works fine
if (t == typeof(FooClass)) {
t.GetMethod("FooMethod").Invoke(null, null); // (null, null) means calling static method with no parameters
}
}
}
Of course in the above example you might as well call FooClass.FooMethod as there is no point using reflection for that. The following sample makes more sense:
public class BarClass {
public void BarMethod(Type t, string method) {
var methodInfo = t.GetMethod(method);
if (methodInfo != null) {
methodInfo.Invoke(null, null); // (null, null) means calling static method with no parameters
}
}
}
public class Foo1Class {
static public Foo1Method(){}
}
public class Foo2Class {
static public Foo2Method(){}
}
//Usage
new BarClass().BarMethod(typeof(Foo1Class), "Foo1Method");
new BarClass().BarMethod(typeof(Foo2Class), "Foo2Method");
Note, that as 10 years have passed. Personally, I would add extension method:
public static TR Method<TR>(this Type t, string method, object obj = null, params object[] parameters)
=> (TR)t.GetMethod(method)?.Invoke(obj, parameters);
and then I could call it with:
var result = typeof(Foo1Class).Method<string>(nameof(Foo1Class.Foo1Method));
Check into the MethodInfo class and the GetMethod() methods on Type.
There are a number of different overloads for different situations.

Categories

Resources