Build Autofixture Customization Using Reflection - c#

I'm trying to create an AutoFixture.ICustomization that loops over every type that inherits from my model base and then explicitly doesn't assign any values to properties that also derive from that model base.
Obviously, this requires some serious abuse of reflection.
So far, I've got this:
public class DiscosModelFixtureCustomizationNoLinks: ICustomization
{
public void Customize(IFixture fixture)
{
Type[] discosModelTypes = typeof(DiscosModelBase).Assembly.GetTypes().Where(t => t.IsDiscosModel() && !t.IsAbstract).ToArray();
MethodInfo customizeMethod = fixture.GetType().GetMethods().Single(m => m.Name == nameof(fixture.Customize) && m.IsGenericMethod); // Needed to resolve overload with generic
foreach (Type t in discosModelTypes)
{
MethodInfo constructedCustomizeMethod = customizeMethod.MakeGenericMethod(t);
Type customizationComposer = typeof(ICustomizationComposer<>).MakeGenericType(t);
PropertyInfo[] propsToIgnore = t.GetProperties().Where(p => p.PropertyType.IsDiscosModel()).ToArray();
foreach (PropertyInfo prop in propsToIgnore)
{
// I want to essentially do this
// For every prop that derives from DiscosModelBase
// fixture.Customize<DiscosObject>(c => c.Without(p => p.Id));
// Using my constructed method
constructedCustomizeMethod.Invoke(fixture, new [] {myExpression});
}
}
}
}
So .Customize<T>() has this signature:
void Customize<T>(Func<ICustomizationComposer<T>, ISpecimenBuilder> composerTransformation);
And ICustomizationComposer<T>.Without() has this signature:
IPostprocessComposer<T> Without<TProperty>(Expression<Func<T, TProperty>> propertyPicker);
So essentially, I need to work out how to build the equivalent of c => c.Without(p => p.Id) using reflection and my PropertyInfo.
This answer would indicated that I can manually build the expression tree, however, it's not really explained in enough detail that I'm able to apply it in this context.
First up, is this possible? Secondly, if so, how do I accomplish this missing step?

So it seems as though I was massively overcomplicating this. Following some assistance from the dev behind AutoFixture, it's been made clear that what I'm trying to accomplish can be done through the use of an Omitter.
This Omitter requires a PropertySpecification which requires an instance of IEquatable<PropertyInfo> to tell it which properties to ignore.
So putting all of that together inside a customizer gives us:
public class DiscosModelFixtureCustomizationNoLinks: ICustomization
{
public void Customize(IFixture fixture)
{
var omitter = new Omitter(new PropertySpecification(new DiscosModelPropertyComparer()));
fixture.Customizations.Add(omitter);
}
private class DiscosModelPropertyComparer : IEquatable<PropertyInfo>
{
public bool Equals(PropertyInfo other) => other.PropertyType.IsDiscosModel();
}
}
For completeness, IsDiscosModel() is:
public static class TypeExtensions
{
public static bool IsDiscosModel(this Type t) =>
t.IsAssignableTo(typeof(DiscosModelBase)) ||
t.HasElementType && t.GetElementType()!.IsAssignableTo(typeof(DiscosModelBase)) ||
t.IsCollectionType() && t.IsGenericType && t.GetGenericArguments().Single().IsAssignableTo(typeof(DiscosModelBase));
}
Extra Info
It's worth noting that, while I didn't need it, the linked discussion shows how PropertySpecifications can be combined together with and and or statements to develop complex conditions for Omitters. For instance, if we take a type comparer that matches a given base type:
public class DeclaringTypeComparer : IEquatable<PropertyInfo>
{
public DeclaringTypeComparer(Type declaringType)
{
this.DeclaringType = declaringType;
}
public Type DeclaringType { get; }
public bool Equals(PropertyInfo other)
{
return other.DeclaringType == this.DeclaringType;
}
}
This can then be combined to ignore all properties inherited from base type and one specific property of a child type.
var spec = new OrRequestSpecification(
new PropertySpecification(new DeclaringTypeComparer(typeof(BaseType))),
new AndRequestSpecification(
new PropertySpecification(
new DeclaringTypeComparer(typeof(ChildType))),
new PropertySpecification(
new PropertyTypeAndNameCriterion(
new Criterion<Type>(typeof(IReadOnlyList<int>), EqualityComparer<Type>.Default),
new Criterion<string>("Numbers", StringComparer.Ordinal)))));
var omitter = new Omitter(spec);
var fixture = new Fixture();
fixture.Customizations.Insert(0, omitter);

Related

Constraining generic types by extrinsic functionality

Background:
I am working with an organization that has an ever-growing collection of data types that they need to extract data from. I have no ability to change these data types. Some are machine-generated from XML files provided by other organizations; some are controlled by intransigent internal dev teams; and some are so old that no one is willing to change them in any way for fear that it will destabilize the entire Earth and cause it to crash into the sun. These classes don't share any common interface, and don't derive from any common type other than object. A few sample classes are given below for illustration purposes:
public class Untouchable
{
public string Data;
}
public class Unchangeable
{
public int Info;
}
The good news is that most of the time, I can use canned functionality to get at least some of the data from instances of the various classes. Unfortunately, most of these classes also have weird and specialized data that needs class-specific logic to extract data from. Also, information often needs to persist inside of the data extractors because the data objects I'm pulling data from have "interactions" (don't ask).
I have created an abstract generic Extractor<T> class to serve as a repository of common methodology, and an IExtractor<T> interface to serve as a convenient handle to access functionality. I also have a few specific (de-generic?) implementations of this class that can extract information from the business objects built from some of the data types. Here's some sample code to illustrate:
public interface IExtractor<T>
{
string ExtractionOne(T something);
string ExtractionTwo(T something);
}
public abstract class Extractor<T> : IExtractor<T>
{
private string internalInfo; // Certain business logic requires us to keep internal info over multiple objects that we extract data from.
protected Extractor() { internalInfo="stuff"; }
public virtual string ExtractionOne(T something)
{
return "This manipulation is generally applicable to most conceivable types.";
}
public abstract string ExtractionTwo(T something); // This DEFINITELY needs to be overridden for each class T
}
public class UntouchableExtractor : Extractor<Untouchable>
{
public UntouchableExtractor() : base() { }
public override string ExtractionTwo(Untouchable something)
{
return something.Data;
}
}
public class UnchangeableExtractor : Extractor<Unchangeable>
{
public UnchangeableExtractor() : base() { }
public override string ExtractionTwo(Unchangeable something)
{
return something.Info.ToString();
}
}
I don't yet support all of the available data types, but management wants to roll out the data extractor to end-users using a command-line interface. They're telling me that we should start extracting the data we can extract, and get to the rest later. Support for the many unmodifiable types will be added by me and by and other programmers as time permits, and the end-users are expected to work around our latency. This actually makes sense in our real-world setting, so just go with it.
The Problem:
The list of data types that we want to pull information from is very large. Maintaining an explicit list of supported types in code will be tricky and error prone -- especially if we find any problems with specific data extractors and need to revoke support until we fix some bugs.
I would like to support the large and changing list of supported data types from a single entry point that dynamically determines the "right version" of IExtractor<> to use based on a passed in dynamic dataObject. If there is no class that implements the IExtractor<> to support the given dataObject, than an error should be thrown.
What Doesn't Work:
I tried taking a dynamic thing and using typeof(Extractor<>).MakeGenericType(thing.GetType()) to create an instance of Extractor<Untouchable> or Extractor<Unchangeable>, but those are abstract classes, so I can't use Activator.CreateInstance() to build an instance of those classes. The core issue with this approach is that it's unfortunately looking for a class of the form Extractor<> instead of an interface of the form IExtractor<>.
I considered putting extension methods like IExtractor<T> BuildExtractor(this T something) in some class, but I'm nervous about running into some business logic called BuildExtractor that already exists in one of these untouchable classes. This may be an unhealthy level of paranoia, but that's where I'm at.
Where I need help:
I'd welcome any suggestions for how I can create a single entrypoint for an unconstrained collection of classes. Thanks in advance.
Combining some code from StackOverflow and my own testing, I suggest using Reflection to find all types implementing an interface:
public static class TypeExt {
public static bool IsBuiltin(this Type aType) => new[] { "/dotnet/shared/microsoft", "/windows/microsoft.net" }.Any(p => aType.Assembly.CodeBase.ToLowerInvariant().Contains(p));
public static IEnumerable<Type> ImplementingTypes(this Type interfaceType, bool includeAbstractClasses = false, bool includeStructs = false, bool includeSystemTypes = false, bool includeInterfaces = false) =>
AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(a => a.GetLoadableTypes())
.Distinct()
.Where(aType => (includeAbstractClasses || !aType.IsAbstract) &&
(includeInterfaces ? aType != interfaceType : !aType.IsInterface) &&
(includeStructs || !aType.IsValueType) &&
(includeSystemTypes || !aType.IsBuiltin()) &&
interfaceType.IsAssignableFrom(aType) &&
aType.GetInterfaces().Contains(interfaceType));
}
public static class AssemblyExt {
//https://stackoverflow.com/a/29379834/2557128
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
if (assembly == null)
throw new ArgumentNullException("assembly");
try {
return assembly.GetTypes();
} catch (ReflectionTypeLoadException e) {
return e.Types.Where(t => t != null);
}
}
}
Reflection can be quite slow, and in my testing, getting all loaded types was the slowest part, so I added caching of the loaded types and the implementing types, but this does mean you will need to refresh the loaded types if you dynamically load assemblies:
public static class TypeExt {
public static bool IsBuiltin(this Type aType) => new[] { "/dotnet/shared/microsoft", "/windows/microsoft.net" }.Any(p => aType.Assembly.CodeBase.ToLowerInvariant().Contains(p));
static Dictionary<Type, HashSet<Type>> FoundTypes = null;
static List<Type> LoadableTypes = null;
public static void RefreshLoadableTypes() {
LoadableTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetLoadableTypes()).ToList();
FoundTypes = new Dictionary<Type, HashSet<Type>>();
}
public static IEnumerable<Type> ImplementingTypes(this Type interfaceType, bool includeAbstractClasses = false, bool includeStructs = false, bool includeSystemTypes = false, bool includeInterfaces = false) {
if (FoundTypes != null && FoundTypes.TryGetValue(interfaceType, out var ft))
return ft;
else {
if (LoadableTypes == null)
RefreshLoadableTypes();
var ans = LoadableTypes
.Where(aType => (includeAbstractClasses || !aType.IsAbstract) &&
(includeInterfaces ? aType != interfaceType : !aType.IsInterface) &&
(includeStructs || !aType.IsValueType) &&
(includeSystemTypes || !aType.IsBuiltin()) &&
interfaceType.IsAssignableFrom(aType) &&
aType.GetInterfaces().Contains(interfaceType))
.ToHashSet();
FoundTypes[interfaceType] = ans;
return ans;
}
}
}
public static class AssemblyExt {
//https://stackoverflow.com/a/29379834/2557128
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
if (assembly == null)
throw new ArgumentNullException("assembly");
try {
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e) {
return e.Types.Where(t => t != null);
}
}
}
Once you have one of these, you can make a factory method that takes a dynamic object:
public static class ImplementingFactory {
public static Type ExtractorType(dynamic anObject) {
Type oType = anObject.GetType();
var iType = typeof(IExtractor<>).MakeGenericType(oType);
var ans = iType.ImplementingTypes().FirstOrDefault();
if (ans == null)
throw new Exception($"Unable to find IExtractor<{oType.Name}>");
else
return ans;
}
}
The following snippet will create the concrete instance of Extractor<T> class and dynamically invokes a method of this instance
var test = new Unchangeable();
var baseType = typeof(Extractor<>).MakeGenericType(test.GetType());
var extractorType = Assembly.GetExecutingAssembly()
.GetTypes().FirstOrDefault(t => t.IsClass && !t.IsAbstract && t.IsSubclassOf(baseType));
if (extractorType != null)
{
dynamic extractor = Activator.CreateInstance(extractorType);
string result = extractor?.ExtractionTwo(test);
}
Of course, it's simplified, you can pass a specific instance of Unchangeable or Untouchable class and restrict assembly types scanning (and get all types only once).
The disadvantage here is that you have to pay attention to ExtractionOne and ExtractionTwo signatures, since they are invoked on dynamic object
The core issue with this approach is that it's unfortunately looking
for a class of the form Extractor<> instead of an interface of the
form IExtractor<>.
This snippet can help you to look through types using IExtrator<> interface
var baseType = typeof(IExtractor<>).MakeGenericType(typeof(Unchangeable));
var extractorType = Assembly.GetExecutingAssembly()
.GetTypes().FirstOrDefault(t => t.IsClass && !t.IsAbstract && baseType.IsAssignableFrom(t));

Look-up table in C# with Types and Actions

I want to change my many if to a look-up table.
I have types and methods. I want to pair them.
if (propertyType == typeof(bool) || propertyType == typeof(bool?))
DoBool(propertyType);
if (propertyType == typeof(DateTime) || propertyType == typeof(DateTime?))
DoDateTime(propertyType);
if (propertyType == typeof(Guid) || propertyType == typeof(Guid?))
DoGuid(propertyType);
I have to create a Dictionary<Type, Action>()? Or which is the best elegant way to do this?
Can you offer me some suggestion where can I start or where can I find the solution?
Since this is more about controlling the flow of the code than pure lookup, I would probably use an object oriented approach and put the code for each "handler" inside separate classes (with common stuff inside a base class).
You can create a common interface like
public interface ITypeHandler {
void HandleType(Type type);
}
... and put the implementation of the handlers inside a dictionary of type Dictionary<Type, ITypeHandler> if you like, or you can have a property on the interface revealing which type it handles and select from a list of (perhaps Dependency Injected) handlers based on this property.
This adds benefits such as separation of concerns, testability, etc.
(Note that *Handler isn't a very good name, you will have to create a better name based on the scenario you're covering.)
You can create a Dictionary<Type, Action<Type>>:
var dict = new Dictionary<Type, Action<Type>>() {
{typeof(bool), DoBool},
{typeof(bool?), DoBool},
{typeof(DateTime), DoDateTime},
{typeof(Datetime?), DoDateTime},
{typeof(Guid), DoGuid},
{typeof(Guid?), DoGuid}
};
And then call it like this:
dict[propertyType](propertyType)
You could create a method for initializing your lookup table with the specified type, to avoid repeating.
private readonly IDictionary<Type, Action<Type>> _lookup;
then you can define method for initializing the _dict,
private void AddEntry<T>(Action<Type> action) where T : struct
{
_lookup[typeof(T)] = action;
_lookup[typeof(Nullable<T>)] = action;
}
private void DoInt(Type type) { /* implementation */ }
AddEntry<bool>(type => { /* implementation */ });
AddEntry<int>(DoInt);
I created my own implementation which is little bit different, but I used #DaggeJ suggestion, so thanks!
First I created a base handler class. After that I used this base on different type classes. You can see it below.
BaseClass:
public abstract class QueryHandler<T> where T : class
{
//I added here more property.
public abstract Type[] Types { get; }
protected QueryHandler(//Properties)
{
//Properties null check
}
public abstract IQueryable<T> Handle();
}
Descendant class:
internal class GuidQuery<T> : QueryHandler<T> where T : class
{
public override Type[] Types => new Type[] { typeof(Guid), typeof(Guid?) };
public GuidQuery(//Properties) : base(//Properties)
{
}
public override IQueryable<T> Handle()
{
// Implementation
}
}
Usage:
public IQueryable<T> GetQuery()
{
var queryHandlerList = new List<QueryHandler<T>>()
{
new IntQuery<T>(//Properties),
new DateTimeQuery<T>(//Properties),
new StringQuery<T>(//Properties),
new BoolQuery<T>(//Properties),
new GuidQuery<T>(//Properties),
new EnumQuery<T>(//Properties)
};
}
return query = queryHandlerList.FirstOrDefault(h => GetType<T>(h, property.PropertyType)).Handle();
private bool GetType<T>(QueryHandler<T> handler, Type type) where T: class
{
if (handler.Types.FirstOrDefault(t => t == type) == type || handler.Types.FirstOrDefault(t => t == type.BaseType) == type.BaseType) return true;
return false;
}

How to pass a type to the method/function call?

I want to make this code shorter, via passing the type as a parameter to targetUnitOfWork.Query.
There are two types SomeListItem and SomeList. And depending on the actual type I have to call either Query<SomeListItem> or Query<SomeList> as it is shown below.
Type typeName = targetClassInfo.ClassType;
if (typeName.Equals(typeof(SomeListItem)))
{
target = targetUnitOfWork
.Query<SomeListITem>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
else if (typeName.Equals(typeof(SomeList)))
{
target = targetUnitOfWork
.Query<SomeList>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
else
{
target = targetClassInfo.CreateNewObject(targetUnitOfWork);
}
How can I solve this task?
Preface
We will not cover in this answer the design decision made by the authors of the code. It's only worth to say that this kind of heterogeneous generics should be left to pattern matching mechanism instead of polymorphic one.
Motivation
Either way, there are plenty of cases where you want to dynamically put generic types and invoke methods in the chain. It's mostly done in projects serving libraries and frameworks for later usage, where parameters are inherited from the user input, or they come lately to the project as an extension by the developers.
Reflection
Luckily, .NET Framework (and Core as well, the code bellow is .NET Framework) provides a rich Reflection library where you can do your metaprogramming model.
The Reflection library provides a way to introspect the program, compromising the static typization in favor of dynamic one e.g. to find a method by its name, because it comes from the user input. It's not its sole purpose, but we will use it this way.
Action in code
In our scenario, we need to call the Query<T> method with arbitrary <T> which comes from the user input. So let's define a function that will serve this functionality. We will call it Test:
static void Test(Type type, TestGenerics testGenerics, String otherObjectName)
It receives the System.Type, an object in our case TestGenerics and a String to test the name property as in the question.
Our TestGenerics object is a fake class that mimics the question's semantics:
class TestGenerics
{
public IEnumerable<T> Query<T>() where T : new()
{
return Enumerable.Repeat(new T(), 10);
}
}
First of all, we need to find the Query method by name. Since it's the one and only method named this way (no overloads) we can safely use FirstOrDefault:
Object enumerable = testGenerics.GetType().GetMethods().FirstOrDefault(m => m.Name == "Query")
But we cannot invoke it directly, as it accepts not only arguments, but generic parameters as well. We can provide them, by providing Type to MakeGenericMethod(Type) reflection's method:
.MakeGenericMethod(type)
And then we are ready to Invoke it without arguments (as it does not accept any), but we need to specify the object it will be invoked from (in our case testGenerics):
.Invoke(testGenerics, null);
Cool so far, there are the dragons to come here, because we need now to build the i => i.name == otherObjectName lambda. The Where method from IEnumerable<T> extensions (in fact, it's a static method in System.Linq.Enumerable) receives a Func<T, R> instead of Predicate<T>, so we need to build one:
Type predicateType = typeof(Func<,>).MakeGenericType(type, typeof(bool));
This builds Func<,> e.g. a Func type with two generic parameters. The first is the type passed, and the second is boolean to mimic a predicate by function.
Now we need to build the lambdas left side by making a parameter of the given type:
ParameterExpression predParam = Expression.Parameter(type, "i");
And getting the field name from it them:
Expression left = Expression.Field(predParam, type.GetField("name"));
And the right side of the expressions is the name we will compare it with:
Expression right = Expression.Constant(otherObjectName, typeof(string));
Building the whole lambda is the next step. From the predicate type (Func<T, R>, the equality expression and the predicate param "i"):
LambdaExpression lambda = Expression.Lambda(predicateType, Expression.Equal(left, right), predParam);
Now we need to find the Where method. It's in the class containing all the extension methods and not in the IEnumerable interface:
IEnumerable<MethodInfo> methodsEnumerable = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public);
MethodInfo where = methodsEnumerable.Where(m => m.GetParameters().Length == 2).FirstOrDefault(m => m.Name == "Where");
But this is a generic method, receiving the type from the input, so we need to do this as well:
MethodInfo genericWhere = where.MakeGenericMethod(type);
Since it is a static method, the object must be passed as an argument (as for the semantics of an extension method). The first argument in the object array is the extension interface (IEnumerable e.g. the return type of Query) and the second argument is the above lambda - compiled:
Object response = genericWhere.Invoke(enumerable, new[] {enumerable, lambda.Compile()});
And here we will stop with the example. You will need to tweak it for your case and add the other method calls. It's very verbose and ugly as well, but will work for any kind of objects containing the name field. In bigger scenarios, if you don't couple to a certain field hardcoded, it will work for wide variety of inputs. The same way how frameworks works with our code.
The full example you can find below:
class TypeOne
{
public string name;
}
class TypeTwo
{
public string name;
}
internal class Program
{
public static void Main(string[] args)
{
Test(typeof(TypeOne), new TestGenerics(), "John");
Test(typeof(TypeTwo), new TestGenerics(), "Smith");
}
static void Test(Type type, TestGenerics testGenerics, String otherObjectName)
{
Object enumerable = testGenerics.GetType().GetMethods().FirstOrDefault(m => m.Name == "Query")
.MakeGenericMethod(type)
.Invoke(testGenerics, null);
Type predicateType = typeof(Func<,>).MakeGenericType(type, typeof(bool));
ParameterExpression predParam = Expression.Parameter(type, "i");
Expression left = Expression.Field(predParam, type.GetField("name"));
Expression right = Expression.Constant(otherObjectName, typeof(string));
LambdaExpression lambda = Expression.Lambda(predicateType, Expression.Equal(left, right), predParam);
IEnumerable<MethodInfo> methodsEnumerable = typeof(System.Linq.Enumerable)
.GetMethods(BindingFlags.Static | BindingFlags.Public);
MethodInfo where = methodsEnumerable.Where(m => m.GetParameters().Length == 2).FirstOrDefault(m => m.Name == "Where");
MethodInfo genericWhere = where.MakeGenericMethod(type);
Object response = genericWhere.Invoke(enumerable, new[] {enumerable, lambda.Compile()});
Console.WriteLine(response);
}
}
class TestGenerics
{
public IEnumerable<T> Query<T>() where T : new()
{
return Enumerable.Repeat(new T(), 10);
}
}
Why don't use generic method like this:
private void SomeMethod<T>()
{
target = targetUnitOfWork
.Query<T>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
Then you can call SomeMethod<SomeList>() or SomeMethod<SomeListItem>()
This is what you want to do, right?
class Program
{
static void Main(string[] args)
{
List<object> listOfObjects = new List<object>() { new Item(), new Dog(), new Cat(), new Human() };
Dog martin = GetFirstOrDefault<Dog>(listOfObjects);
}
static T GetFirstOrDefault<T>(List<object> listOfObjects)
{
return (T)listOfObjects.Where(x => x.GetType() == typeof(T)).FirstOrDefault();
}
}
class Item
{
public string Name { get; set; }
public string Color { get; set; }
}
class Dog
{
public string Name { get; set; }
public int Age { get; set; }
}
class Cat
{
public string Name { get; set; }
public int Age { get; set; }
}
class Human
{
public string Name { get; set; }
public DateTime Birth { get; set; }
}
Things are only going to get complicated (messy?) from here on.
Ok, so first two queries are same. So, you might go for a generic method. Something of this sort:
public IEnumerable<T> GetListTarget<T>(bool applyWhere) // You will need to add an constraint here that is applicable to both classes. Only then compiler will be able to understand the properties you are using in the where method
{
if (applyWhere)
{
return targetUnitOfWork
.Query<T>()
.Where(i => i.Name.Equals(otherObj.Name)).Where(j => j.SortKey == otherObj.SortKey);
}
else
{
return targetClassInfo.CreateNewObject(targetUnitOfWork);
}
}

Using reflection to invoke generic method passing lambda expression

I have few classes deriving from abstract class A - A1, A2, A3, etc.
I need to register these classes to BsonClassMap using their own discriminators using code like this:
BsonClassMap.RegisterClassMap<A1>(cm =>
{
cm.AutoMap();
cm.SetDiscriminator(discriminator)
});
Since I will have more of such classes in future, I want to use reflection to do that:
foreach (var type in Assembly.GetAssembly(typeof(A))
.GetTypes().Where(t => t.IsClass
&& !t.IsAbstract
&& t.IsSubclassOf(typeof(A))))
{
var discriminator = type.GetField("Discriminator")
.GetRawConstantValue()
.ToString();
var method = typeof(BsonClassMap).GetMethods()
.FirstOrDefault(m => m.IsGenericMethod
&& m.Name == "RegisterClassMap");
if (method == null) continue;
var generic = method.MakeGenericMethod(type);
generic.Invoke(this, null);
}
How can I pass such lambda expression to this function?
cm =>
{
cm.AutoMap();
cm.SetDiscriminator(discriminator)
});
I have found many descriptions of how to call generic methods, but can't get this to work.
In addition to the answer posted by #aL3891, I mocked up a simple example of how I would call this like so:
In this situation, SampleClass is the standin for BsonClassMap, and AbstractClass stands in for A, etc
class Program
{
static void Main(string[] args)
{
SampleClass.Foo<int>(param =>
{
});
var discoveredTypes = new List<Type>
{
typeof(DerivedOne),
typeof(DerivedTwo),
typeof(DerivedThree)
};
foreach (var type in discoveredTypes)
{
var methodType = typeof(Program).GetMethods().FirstOrDefault(x => x.Name == "CreateMethod").MakeGenericMethod(type);
var method = methodType.Invoke(null, null);
var staticMethod = typeof(SampleClass).GetMethods().FirstOrDefault(x => x.Name == "Foo").MakeGenericMethod(type);
staticMethod.Invoke(null, new object[] { method });
}
Console.ReadKey();
}
public static Action<T> CreateMethod<T>()
{
return new Action<T>((param) =>
{
Console.WriteLine("This is being invoked with type: " + typeof(T).Name);
});
}
}
public abstract class AbstractClass { }
public class DerivedOne : AbstractClass { }
public class DerivedTwo : AbstractClass { }
public class DerivedThree : AbstractClass { }
public class SampleClass
{
public static void Foo<TGenericType>(Action<TGenericType> setupMethod)
where TGenericType : new()
{
TGenericType instance = new TGenericType();
setupMethod(instance);
}
}
The problem is that you're trying to go from a runtime declaration to a compile time generic, so it's easy enough to just make a factory style method you can invoke generically to construct the delegate for you. The CreateMethod method in Program would be involved in making your lambda expression, and then you could invoke the static method on BsonClassMap that way.
There are two parts to this question,
To pass a lambda to this method you simply pass it in an array as the second argument to the Invoke call. generic.Invoke(this, new object[]{foo});
However, the problem now is how do you get a object containing a lambda?
This doesn't work var l = () => {...}, so whats the deal?
Well lambdas in c# can have two different types. They can be a a delegate (Func<...>or Action<..> or they can be an expression Expression<Func<...>>
What it actually ends up being depends on what you assign it to, or rather what the compiler infers it to be. So what you have to write to get an expression is Expression<Func<int>> e = () => 3;
Now you can pass e into your invoke call (provided that the expression types match up of course)
If this code is entirely generic, one solution might be to have a helper method that actually returns the expression you pass in:
public Action<T> GetMyDelegate<T>() where T: A{
return (T cm) => {
cm.AutoMap();
cm.SetDiscriminator(discriminator)
};
}
Also note that you can initialize a delegate such as Action with a method name:
public void Method1() {
var a = new Action(Method2);
}
public void Method2()
{ }
You can also create a delegate from a MethodInfo, say if different subtypes of A have their own init method that you find with reflection:
http://msdn.microsoft.com/en-us/library/53cz7sc6.aspx

Is there any way to infer an Action type, or a full Action?

I find myself (too) often using a construct like the following:
class MyClass
{
public TypeA ObjectA;
public TypeB ObjectB;
public TypeC ObjectC;
public List<TypeD> ListOfObjectD = new List<TypeD>();
public void DoSmth()
{
return SomeConstruct(
/*...*/
new Setter<TypeA>(a => ObjectA = a), // these are the
new Setter<TypeB>(b => ObjectB = b), // things I'm trying
new Setter<TypeC>(c => ObjectC = c), // to make shorter
new Setter<TypeD>(d => ListOfObjectD.Add(d)),
/*...*/
);
}
}
class Setter<T>
{
public Action<T> Action;
public Setter(Action<T> action)
{
Action = action;
}
}
Is there any way for the Setter class to infer the type of the Action and create the standard (T obj) => Member = obj Action by only passing the Member in some way? I'm thinking of something like:
new Setter(ObjectA)
which of course is not valid syntax, but should give you an idea what I'm trying to achieve. I'm using this construct literally hundreds of time in my code, so the code
saved by this small change would be tremendous.
Edit: Added the TypeD example. The part
new Setter<TypeD>(d => ListOfObjectD.Add(d))
can be simplified to
new Setter<TypeD>(ListOfObjectD.Add)
which is awesome because it cuts from the redundant code. If only <TypeD> could also be inferred it would be perfect. I'm looking for something like this for the others.
#Lazarus - basically the purpose is to return setters, so other objects can set certain members of the class (or it can do other stuff defined in the Action) without accessing the class itself, only the Setter object. The full list of reasons is long and convoluted, but the structuring of the program works like a charm and I doubt needs changing (the example of course is simplified and doesn't really make sense as is).
Edit 2: I found a good way to simplify things for List's:
static class SetterHelper
{
public static Setter<T> GetSetter<T>(this List<T> list)
{
return new Setter<T>(list.Add);
}
}
Now I can just use this:
ListOfObjectD.GetSetter()
which works perfectly! why can't I do the same for T directly? I tried this:
static class SetterHelper
{
public static Setter<T> GetSetter<T>(this T item)
{
return new Setter<T>(t => item = t); // THIS DOESN'T SET THE PASSED MEMBER
}
}
Of course it won't work as intended because it will set item, but not the passed member. I tried adding ref as (ref this T item) but it won't compile :(... It would have been perfect.
Best I can offer you is the following syntax:
Setter.For( () => ObjectA );
using this helper class
static class Setter
{
public static Setter<T> For<T>(Expression<Func<T>> e)
{
ParameterExpression[] args = { Expression.Parameter(((e.Body as MemberExpression).Member as FieldInfo).FieldType) };
Action<T> s = Expression.Lambda<Action<T>>(Expression.Assign(e.Body, args[0]), args).Compile();
return new Setter<T>(s);
}
}

Categories

Resources