Dynamically set generic type argument - c#

Following on from my question here, I'm trying to create a generic value equality comparer. I've never played with reflection before so not sure if I'm on the right track, but anyway I've got this idea so far:
bool ContainSameValues<T>(T t1, T t2)
{
if (t1 is ValueType || t1 is string)
{
return t1.Equals(t2);
}
else
{
IEnumerable<PropertyInfo> properties = t1.GetType().GetProperties().Where(p => p.CanRead);
foreach (var property in properties)
{
var p1 = property.GetValue(t1, null);
var p2 = property.GetValue(t2, null);
if( !ContainSameValues<p1.GetType()>(p1, p2) )
return false;
}
}
return true;
}
This doesn't compile because I can't work out how to set the type of T in the recursive call. Is it possible to do this dynamically at all?
There are a couple of related questions on here which I have read but I couldn't follow them enough to work out how they might apply in my situation.

You can avoid reflection on invocation if you are happy to compare based on the statically know types of the properties.
This relies on Expressions in 3.5 to do the one off reflection in a simple manner, it is possible to do this better to reduce effort for extremely nested types but this should be fine for most needs.
If you must work off the runtime types some level of reflection will be required (though this would be cheap if you again cache the per property access and comparison methods) but this is inherently much more complex since the runtime types on sub properties may not match so, for full generality you would have to consider rules like the following:
consider mismatched types to NOT be equal
simple to understand and easy to implement
not likely to be a useful operation
At the point the types diverge use the standard EqualityComparer<T>.Default implementation on the two and recurse no further
again simple, somewhat harder to implement.
consider equal if they have a common subset of properties which are themselves equal
complicated, not really terribly meaningful
consider equal if they share the same subset of properties (based on name and type) which are themselves equal
complicated, heading into Duck Typing
There are a variety of other options but this should be food for thought as to why full runtime analysis is hard.
(note that I have changed you 'leaf' termination guard to be what I consider to be superior, if you want to just use sting/value type for some reason feel free)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Linq.Expressions;
class StaticPropertyTypeRecursiveEquality<T>
{
private static readonly Func<T,T, bool> actualEquals;
static StaticPropertyTypeRecursiveEquality()
{
if (typeof(IEquatable<T>).IsAssignableFrom(typeof(T)) ||
typeof(T).IsValueType ||
typeof(T).Equals(typeof(object)))
{
actualEquals =
(t1,t2) => EqualityComparer<T>.Default.Equals(t1, t2);
}
else
{
List<Func<T,T,bool>> recursionList = new List<Func<T,T,bool>>();
var getterGeneric =
typeof(StaticPropertyTypeRecursiveEquality<T>)
.GetMethod("MakePropertyGetter",
BindingFlags.NonPublic | BindingFlags.Static);
IEnumerable<PropertyInfo> properties = typeof(T)
.GetProperties()
.Where(p => p.CanRead);
foreach (var property in properties)
{
var specific = getterGeneric
.MakeGenericMethod(property.PropertyType);
var parameter = Expression.Parameter(typeof(T), "t");
var getterExpression = Expression.Lambda(
Expression.MakeMemberAccess(parameter, property),
parameter);
recursionList.Add((Func<T,T,bool>)specific.Invoke(
null,
new object[] { getterExpression }));
}
actualEquals = (t1,t2) =>
{
foreach (var p in recursionList)
{
if (t1 == null && t2 == null)
return true;
if (t1 == null || t2 == null)
return false;
if (!p(t1,t2))
return false;
}
return true;
};
}
}
private static Func<T,T,bool> MakePropertyGetter<TProperty>(
Expression<Func<T,TProperty>> getValueExpression)
{
var getValue = getValueExpression.Compile();
return (t1,t2) =>
{
return StaticPropertyTypeRecursiveEquality<TProperty>
.Equals(getValue(t1), getValue(t2));
};
}
public static bool Equals(T t1, T t2)
{
return actualEquals(t1,t2);
}
}
for testing I used the following:
public class Foo
{
public int A { get; set; }
public int B { get; set; }
}
public class Loop
{
public int A { get; set; }
public Loop B { get; set; }
}
public class Test
{
static void Main(string[] args)
{
Console.WriteLine(StaticPropertyTypeRecursiveEquality<String>.Equals(
"foo", "bar"));
Console.WriteLine(StaticPropertyTypeRecursiveEquality<Foo>.Equals(
new Foo() { A = 1, B = 2 },
new Foo() { A = 1, B = 2 }));
Console.WriteLine(StaticPropertyTypeRecursiveEquality<Loop>.Equals(
new Loop() { A = 1, B = new Loop() { A = 3 } },
new Loop() { A = 1, B = new Loop() { A = 3 } }));
Console.ReadLine();
}
}

You need to call the method using reflection, like this:
MethodInfo genericMethod = typeof(SomeClass).GetMethod("ContainSameValues");
MethodInfo specificMethod = genericMethod.MakeGenericMethod(p1.GetType());
if (!(bool)specificMethod.Invoke(this, new object[] { p1, p2 }))
However, your method should not be generic in the first place; it should simply take two object parameters. (Or, if it is generic, it should cache properties and delegates in a generic type)

Related

How to compare the same properties of two different class objects in C#?

I have two classes A and B which have some properties that are the same. I am looking for a way to compare only the same properties and was hoping if there was some nuget package that did this for any type of class.
I don't know how to go about looking for such a nuget package, I already tried using if statements to compare the same properties, but I have a lot of cases like this so it would be easier to use a nuget package to do it.
Also, it is not possible to include inheritance here, as the two classes are not logically linked.
class A {
string title;
DateTime publishDate;
string Author;
int numberOfSales;
}
class B {
DateTime publishDate;
int numberOfSales;
}
I have already did something like this to compare the two same properties
if (A.publishDate.Equals(B.publishDate)) {
// Do something
}
if (A.numberOfSales == B.numberOfSales) {
// Do something
}
I would really be grateful if someone could let me know if there is some nuget package that would just compare the same properties of the two classes.
Why you don't use native interface in c# ?
you can use Icomprable interface like this :
public class A:IComparable<B>
{
public string title;
public DateTime publishDate;
public string Author;
public int numberOfSales;
public int CompareTo(B other)
{
if (this.numberOfSales == other.numberOfSales && this.publishDate.Equals(other.publishDate))
return 0;
if (this.numberOfSales != other.numberOfSales && this.publishDate.Equals(other.publishDate))
return 1;
if (this.numberOfSales == other.numberOfSales && !this.publishDate.Equals(other.publishDate))
return 2;
return -1;
}
}
public class B
{
public DateTime publishDate;
public int numberOfSales;
}
then you can use it like this :
switch (aClass.CompareTo(bClass))
{
case 0:Console.WriteLine("both properties are equal");break;
case 1:Console.WriteLine("PublishDate only equal"); break;
case 2: Console.WriteLine("NumberOfSales only equal"); break;
case -1: Console.WriteLine("None are equal"); break;
}
I hope it will be useful
Just use Reflection.
For example, this class will all fields (because your sample class listings have no Properties, they only have Fields) and return a list of them:
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
public static class Comparer {
public static List<String> Compare<T1, T2>(T1 a, T2 b) {
var result = new List<String>(); // you can choose to return FieldInfo or values or whatever...
// you can also use .GetProperties() if you actually want Properties with getters.
var aFields = typeof(T1).GetFields(BindingFlags.Instance | BindingFlags.Public);
var bFields = typeof(T2).GetFields(BindingFlags.Instance | BindingFlags.Public);
var aCommonFields = new List<FieldInfo>();
var bCommonFields = new List<FieldInfo>();
Func<IEnumerable<FieldInfo>, FieldInfo, bool> predicate = (other, x) => other.FirstOrDefault(z => z.Name == x.Name && z.FieldType == x.FieldType) != null;
aCommonFields.AddRange(aFields.Where(x => predicate(bFields, x)));
bCommonFields.AddRange(bFields.Where(x => predicate(aCommonFields, x)));
foreach(var aCommonField in aCommonFields) {
var bCommonField = bCommonFields.First(bField => predicate(new[]{ aCommonField }, bField));
var aValue = aCommonField.GetValue(a);
var bValue = bCommonField.GetValue(b);
if (aValue.Equals(bValue)) {
result.Add(aCommonField.Name);
}
}
return result;
}
}
Sample usage:
var a1 = new A { numberOfSales = 42 };
var b2 = new B { numberOfSales = 42 };
var commons = Comparer.Compare(a1, b2);
foreach(var common in commons) {
if (common == nameof(A.numberOfSales)) {
Console.WriteLine("Number of sales match!");
}
}
I like a more controlled way better where you just type the compaire properties as you did in your sample, perhaps use an icomparable interface.
he reflection option that is offered and will be offered is slow, could give null pointer exceptions etc but write once work always, it's not a nuget package but here you go.
public static List<PropertyInfo> GetDifferences(object test1, object test2)
{
if (test1 is null)
throw new ArgumentNullException(nameof(test1));
if (test2 is null)
throw new ArgumentNullException(nameof(test2));
List<PropertyInfo> differences = new List<PropertyInfo>();
foreach (PropertyInfo property in test1.GetType().GetProperties())
{
if (test2.GetType().GetProperties().Any(a => a.Name.Equals(property.Name, StringComparison.Ordinal)))
{
object value1 = property.GetValue(test1, null);
object value2 = property.GetValue(test2, null);
if ((value1 == null) || !value1.Equals(value2))
{
differences.Add(property);
}
}
}
return differences;
}
It will return the properties that both have and are not the same.

Dynamically copy certain properties between two class instances

I am attempting to write a piece of code that can take two instances of the same object, and copy some properties from the first one to the second one, dynamically. A little twist is that I only have access to the objects, through an interface they both inherit.
I have created a Copyable attribute that will be used to mark what properties can be copied.
I then managed to successfully do this using the PropertyInfo.GetMethod and PropertyInfo.SetMethod, however the resulting code is too slow. When comparing to statically assigning properties at compile time - this approach is ~20 times slower.
Here is my initial implementation using pure reflection.
using System;
using System.Linq;
namespace ConsoleApp58
{
interface IInterface
{
int Id { get; set; }
}
[AttributeUsage(AttributeTargets.Property)]
class CopyableAttribute : Attribute { }
class Child : IInterface
{
public int Id { get; set; }
[Copyable]
public int CopyableProp { get; set; }
}
class Program
{
static void Main(string[] args)
{
var source = new Child() {Id = 1, CopyableProp = 42};
var target = new Child() {Id = 2, CopyableProp = 0};
CopyProps(source, target);
}
static void CopyProps(IInterface source, IInterface target)
{
var props = target.GetType()
.GetProperties()
.Where(p => p.IsDefined(typeof(CopyableAttribute), false))
.ToArray();
foreach (var prop in props)
{
var value = prop.GetMethod.Invoke(source, new object[] { });
prop.SetMethod.Invoke(target, new [] {value});
}
}
}
}
This works, but its slow, so I decided to attempt and create an expression tree that will build a lambda that can call the getters and setters, however I can't seem to make it work.
I tried following this SO question, however, that implementation relies on the fact that I know what's the type of my object that I'm taking the properties from.
However, in my case the properties are defined as part of child classes, and I have no access to them in my IInterface.
Hence, I'm asking here. Is there a (fast) way for me to copy the value of specific properties, between instances of two objects, by referring to them only through their common interface.
You can generate Action<IInterface, IInterface> by Expression API. Try this code:
private static Expression<Action<IInterface, IInterface>> CreateCopyMethod(Type type)
{
var props = type
.GetProperties()
.Where(p => p.IsDefined(typeof(CopyableAttribute), false))
.ToArray();
var s = Expression.Parameter(typeof(IInterface), "s");
var t = Expression.Parameter(typeof(IInterface), "t");
var source = Expression.Variable(type, "source");
var castToSource = Expression.Assign(source, Expression.Convert(s, type));
var target = Expression.Variable(type, "target");
var castToTarget = Expression.Assign(target, Expression.Convert(t, type));
var instructions = new List<Expression>
{
castToSource, castToTarget
};
foreach (var property in props)
{
var left = Expression.Property(target, property);
var right = Expression.Property(source, property);
var assign = Expression.Assign(left, right);
instructions.Add(assign);
}
var lambda = Expression.Lambda<Action<IInterface, IInterface>>(
Expression.Block(
new[] {source, target}, instructions),
s, t);
return lambda;
}
Usage
IInterface src = new Child
{
CopyableProp = 42
};
IInterface dst = new Child();
var copy = CreateCopyMethod(src.GetType()).Compile();
copy(src, dst);
Console.WriteLine(((Child)dst).CopyableProp); // 42
To improve performance consider usage Dictionary<Type, Action<IInterface, IInterface>> to cache implementation of already generated methods

Compare Two Structs Using Standard Method (Byte Comparison/Reflection) Even If Equals Method Exists

I have some simple struct, which overrides the Equals() method:
public struct Pair<T> {
public Pair(T x, T y) {
X = x; Y = y;
}
public T X { get; }
public T Y { get; }
public override bool Equals(object obj) {
var otherPair = (Pair<T>) obj;
return X.Equals(otherPair.X);
}
}
According to MSDN, value types without an Equals() method are compared as follows:
If none of the fields of the current instance and obj are reference types, the Equals method performs a byte-by-byte comparison of the two objects in memory. Otherwise, it uses reflection to compare the corresponding fields of obj and this instance.
I wish to compare Pairs using the quoted approach instead of using Pair's own Equals() method, so that the following test passes:
[Test]
public void PairsEqual()
{
var p1a = new Pair<int>(10, 1);
var p1b = new Pair<int>(10, 1);
var p2 = new Pair<int>(10, 2);
Assert.That(p1a, Is.Not.EqualTo(p2));
Assert.That(p1a, Is.EqualTo(p1a));
Assert.That(p1a, Is.EqualTo(p1b));
}
This should ultimately work like a ReferenceEqual for structs. Is this possible? Ideally, I would like to replace the comparison with the original ValueType.Equals() method.
Edit:
My real wish is to be able to add a code contract to a class like this:
public class Holder<T> {
private T _item;
public Holder(T item) {
_item = item;
}
public T Item {
get { return _item; }
set {
Contract.Ensures(_item.Equals(value));
_item = value; // <-- imagine this like contained a bug
}
}
}
Imagine I use the holder object like this:
var holder = new Holder<Pair<int>>(p1a);
holder.Item = p2;
If set wasn't _item = value; but rather _item = _item;, the contract wouldn't complain, since the example would use Pair<T>'s Equals() method, which says that p1a and p2 are equal. If it instead use the original ValueType.Equals() method using byte comparison/reflection, the contract would have been violated correctly and the mistake would have been caugt.
Using objects, the contract would instead have been something like Contract.Ensures(ReferenceEqual(_item, value) but that doesn't work for value types (structs).
The point is that I don't know the type of T in Holder<T>, so I cannot introduce my own custom equality comparer, even if I wanted.
This can be done using reflection. The following solution is based on the code from the blog post Strong Typed, High Performance Reflection with C# Delegate, but the code has been shorten to work specifically for ValueType.Equals():
public static Func<ValueType, ValueType, bool> GetValueTypeEquals()
{
var type = typeof(ValueType);
var dynamicMethod = new DynamicMethod("ValueTypeEquals", typeof(bool), new[] { type, typeof(object) }, type);
var il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg, 0);
il.Emit(OpCodes.Ldarg, 1);
il.EmitCall(OpCodes.Call, type.GetMethod(nameof(Equals), Public | Instance, null, new[] { type }, null), null);
il.Emit(OpCodes.Ret);
return (Func<ValueType, ValueType, bool>) dynamicMethod.CreateDelegate(typeof(Func<ValueType, ValueType, bool>));
}
Using the method above to retrieve ValueTypes's Equal() method, the test from the example will look like this:
[Test]
public void PairsEqual()
{
var p1a = new Pair<int>(10, 1);
var p1b = new Pair<int>(10, 1);
var p2 = new Pair<int>(10, 2);
var equals = GetValueTypeEquals();
Assert.That(!equals(p1a, p2));
Assert.That(equals(p1a, p1a));
Assert.That(equals(p1a, p1b));
}

Add intellisense when writing lambda's for an Action<dynamic>

This question is related to this other question.
I have the following method:
public static T GetNewData<T>(params Action<dynamic>[] actions) where T : class, new()
{
dynamic dynamicData = new DeepObject();
foreach (var action in actions)
{
action(dynamicData);
}
return Converter.Convert<T>(dynamicData);
}
The users of this method will include less technical people, even non-developers and as such the easier writing calls to this method is the better. My sticking point right now is that by using Action<dynamic> as the parameter type there is no intellisense provided to the user. In the context I know that the intellisense should be acting as if the dynamic was in fact T.
So is their a way I could either: Tell Visual Studio to use type T for the intellisense or change the parameter to be Action<T> and somehow programmatically change it to be Action<dynamic> or Action<DeepObject> so that the call to it will succeed?
EDIT: To clarify, the types that I am using for T are not of type DeepObject and they do not inherit any standard interface, the use of DeepObject is to allow setting up nested types without the user needing to explicitly instantiate at each level. This was the original usage before adding the dynamic and DeepObject code:
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>(
x => x.Property1 = ExampleDataFactory.GetNewData<Property1Type>(),
x => x.Property1.Property2 = ExampleDataFactory.GetNewData<Property2Type>(),
x => x.Property1.Property2.Property3 = ExampleDataFactory.GetNewData<Property3Type>(),
x => x.Property1.Property2.Property3.Property4 = true);
Here is what it looks like now:
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>(
x => x.Property1.Property2.Property3.Property4 = true);
EDIT: Here is the fully implemented solution based on nmclean's answer
public static DataBuilder<T> GetNewData<T>() where T : class, new()
{
return new DataBuilder<T>();
}
The DataBuilder Class:
public class DataBuilder<T>
{
public readonly T data;
public DataBuilder()
{
data = Activator.CreateInstance<T>();
}
public DataBuilder(T data)
{
this.data = data;
}
public DataBuilder<T> SetValue<T2>(Expression<Func<T, T2>> expression, T2 value)
{
var mExpr = GetMemberExpression(expression);
var obj = Recurse(mExpr);
var p = (PropertyInfo)mExpr.Member;
p.SetValue(obj, value);
return this;
}
public T Build()
{
return data;
}
public object Recurse(MemberExpression expr)
{
if (expr.Expression.Type != typeof(T))
{
var pExpr = GetMemberExpression(expr.Expression);
var parent = Recurse(pExpr);
var pInfo = (PropertyInfo) pExpr.Member;
var obj = pInfo.GetValue(parent);
if (obj == null)
{
obj = Activator.CreateInstance(pInfo.PropertyType);
pInfo.SetValue(parent, obj);
}
return obj;
}
return data;
}
private static MemberExpression GetMemberExpression(Expression expr)
{
var member = expr as MemberExpression;
var unary = expr as UnaryExpression;
return member ?? (unary != null ? unary.Operand as MemberExpression : null);
}
private static MemberExpression GetMemberExpression<T2>(Expression<Func<T, T2>> expr)
{
return GetMemberExpression(expr.Body);
}
}
The Usage:
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>()
.SetValue(x=> x.Property1.EnumProperty, EnumType.Own)
.SetValue(x=> x.Property2.Property3.Property4.BoolProperty, true)
.Build();
Do not use Action<dynamic>, use Action<T>with method's constraint where T:DeepObject. Users will get intellisence and ability to use strongly typed objects:
public static DeepObject GetNewData<T>(params Action<T>[] actions)
where T : DeepObject, //restrict user only inheritors of DeepObject
new() //and require constructor
{
var data = new T();
foreach (var action in actions)
{
action(data);
}
return data;
}
Does the user need to access unknown properties or add new ones? If not, using dynamic objects seems like a step backwards. If your desired syntax does compile as an Action<T>, I think you should just declare it that way and then go with your first instinct of using the LINQ Expression API to decide how to interpret the code.
Unfortunately, although statements, such as an assignment, are part of the API, C# doesn't support converting them to expression trees. This is not allowed:
public static T GetNewData<T>(params Expression<Action<T>>[] actions)
where T : class, new() {
...
}
...
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>(
x => x.Property1.Property2.Property3.Property4 = true);
Only single-line expressions that would have a return a value are supported. So I think the best you could do is something like this:
public class Assignment<T> {
public readonly Expression Expression;
public readonly object Value;
public Assignment(Expression<Func<T, object>> expression, object value) {
Expression = expression;
Value = value;
}
}
...
public static T GetNewData<T>(params Assignment<T>[] assignments)
where T : class, new() {
var data = Activator.CreateInstance<T>();
foreach (var assignment in assignments) {
// todo:
// - pull property names from assignment.Expression
// - initialize nested properties / assign to assignment.Value
}
return data;
}
...
ExampleDataFactory.GetNewData<ServicesAndFeaturesInfo>(
new Assignment<ServicesAndFeaturesInfo>(
x => x.Property1.Property2.Property3.Property4, true));
Getting the property names from an expression tree of chained property access is not too complicated. Here is one implementation.
Of course, the new Assignment<ServicesAndFeaturesInfo>(...) is ugly and repetitive, so maybe it could be restructured to something like this:
var newData = ExampleDataFactory.NewData<ServicesAndFeaturesInfo>();
newData.Add(x => x.Property1.Property2.Property3.Property4, true);
newData.Add(...);
...
newData.Get();

How to wrap a static class in a non-static instance object (dynamically)

I have an interesting problem. I need to wrap static classes dynamically. I.e. return a non-static instance to my callers. e.g.:
public object CreateInstance(string className) {
Type t = assembly.GetType(className);
if (IsStatic(t)) {
return CreateStaticWrapper(t);
} else {
return Activator.CreateInstance(t);
}
}
So what I need is pointers as to how to implement CreateStaticWrapper.
Note: I cannot use Dynamic objects unfortunately.
So what are my options? I'm not that keen on learning IL generation? If IL generation (Reflection.Emit, or is there other ways now?) is the way to go does anyone have pointers there?
Edit: It's important to note that I can return a Dictionary of Delegates. So I could use Delegate.CreateDelegate for this but I can't seem to work out how to handle overloaded methods and Generic methods.
Edit2: Another option would be to inject an empty constructor into the type using Emit, again any pointers? Is this even possible on a type marked as static? Does the static keyword make it into the IL?
Edit3: For a bit of context, I'm passing this to a javascript environment see: my project. So I would like to be able to (in JavaScript):
var fileHelper = .create('System.IO.File');
if (fileHelper.Exists(fileName)) { fileHelper.Delete(fileName); }
Thanks All.
Try creating a wrapper class which inherits from System.Dynamic.DynamicObject. In the wrapper class, use reflection to call the methods of the static class.
You need something like this:
public class StaticWrapper<T> : System.Dynamic.DynamicObject
{
private static readonly Type t = typeof(T);
public static int MyProperty { get; set; }
public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result)
{
try
{
result = t.InvokeMember(binder.Name, BindingFlags.Static | BindingFlags.Public, null, null, args);
return true;
}
catch
{
result = null;
return false;
}
}
public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result)
{
try
{
var p = t.GetProperty(binder.Name);
if (p != null)
result = p.GetValue(null, null);
else
{
var f = t.GetField(binder.Name);
if (f != null) result = f.GetValue(null);
else { result = null; return false; }
}
return true;
}
catch
{
result = null;
return false;
}
}
public override bool TrySetMember(System.Dynamic.SetMemberBinder binder, object value)
{
try
{
var p = t.GetProperty(binder.Name);
if (p != null)
p.SetValue(null, value, null);
else
{
var f = t.GetField(binder.Name);
if (f != null) f.SetValue(null, value);
else return false;
}
return true;
}
catch (SystemException)
{
return false;
}
}
}
Hope it works.
I'd say go for IL generation. Creating a proxy is a pretty simple scenario. I actually wrote a blog post about it: einarwh.posterous.com/patching-polymorphic-pain-at-runtime. The scenario is different, but the solution almost identical.
You can basically do exactly as in the blog post, except you don't need to load the 'this' reference onto the stack (since you're doing static method calls).
Ok, well the solution I've come up with is as follows and was found reading through and studying Einar's blog post which he posted as a comment above. Thanks Einar.
But I thought I'd post my full code solution here in case it may help someone in the future:
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace js.net.jish.Command
{
public class StaticTypeWrapper
{
private readonly Type staticType;
public StaticTypeWrapper(Type staticType)
{
this.staticType = staticType;
}
public object CreateWrapper()
{
string ns = staticType.Assembly.FullName;
ModuleBuilder moduleBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(ns), AssemblyBuilderAccess.Run).DefineDynamicModule(ns);
TypeBuilder wrapperBuilder = moduleBuilder.DefineType(staticType.FullName, TypeAttributes.Public, null, new Type[0]);
foreach (MethodInfo method in staticType.GetMethods().Where(mi => !mi.Name.Equals("GetType")))
{
CreateProxyMethod(wrapperBuilder, method);
}
Type wrapperType = wrapperBuilder.CreateType();
object instance = Activator.CreateInstance(wrapperType);
return instance;
}
private void CreateProxyMethod(TypeBuilder wrapperBuilder, MethodInfo method)
{
var parameters = method.GetParameters();
var methodBuilder = wrapperBuilder.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, parameters.Select(p => p.ParameterType).ToArray());
var gen = methodBuilder.GetILGenerator();
for (int i = 1; i < parameters.Length + 1; i++)
{
gen.Emit(OpCodes.Ldarg, i);
}
gen.Emit(OpCodes.Call, method);
gen.Emit(OpCodes.Ret);
}
}
}
So, say that we play around with the "Delegate.CreateDelegate" way. And let's see if we can get more details about your other issues after that... Let's start with:
public static object Generate(Type t)
{
if(IsStatic(t))
{
var dictionary = new Dictionary<string, Delegate>();
foreach (var methodInfo in t.GetMethods())
{
var d = Delegate.CreateDelegate(t, methodInfo);
dictionary[methodInfo.Name] = d;
}
return dictionary;
}
return Activator.CreateInstance(t);
}
Static classes are 'sealed' and can thus not be inherited. So I don't see what you mean by 'overloaded'. For generic methods, we need to invoke the methodInfo.MakeGenericMethod(...) before adding it to our dictionary. But then you would need to know the type beforehand, which I guess you don't... Alternatively, you can do something like:
...
if (methodInfo.IsGenericMethod)
{
d = new Func<MethodInfo, Type[], Delegate>(
(method, types) =>
Delegate.CreateDelegate(
method.DeclaringType, method.MakeGenericMethod(types)));
}
dictionary[methodInfo.Name] = d;
...
That would give you a delegate that would take a type array (the generic type parameters), and produce a working delegate from that.

Categories