Create type with internal constructor and self referencing constructor parameter type in AutoFixture - c#

We are using AutoFixture.AutoMoq 4.17.0.
The following code throws an exception during Create:
AutoFixture.ObjectCreationExceptionWithPath: AutoFixture was unable to
create an instance from
XXX.TypeWithInternalConstructor,
most likely because it has no public constructor, is an abstract or
non-public type.
[TestClass]
public class AutoFixtureExperiments
{
[TestMethod]
public void ShouldActivateTypesWithInternalConstructor()
{
var fixture = new Fixture();
fixture
.Behaviors.OfType<ThrowingRecursionBehavior>().ToList()
.ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new OmitOnRecursionBehavior(2));
fixture.ResidueCollectors.Add(
new Postprocessor(
new MethodInvoker(
new ModestInternalConstructorQuery()),
new AutoPropertiesCommand()
));
var result = fixture.Create<TypeWithInternalConstructor>();
Assert.AreNotEqual(0, result.Property);
}
}
public class ModestInternalConstructorQuery : IMethodQuery
{
public IEnumerable<IMethod> SelectMethods(Type type)
{
if (type == null) throw new ArgumentNullException(nameof(type));
return from ci in type.GetConstructors(BindingFlags.Instance | BindingFlags.NonPublic)
where ci.IsAssembly // Take internal constructors only
let parameters = ci.GetParameters()
//where parameters.All(p => p.ParameterType != type)
orderby parameters.Length ascending
select new ConstructorMethod(ci) as IMethod;
}
}
public class TypeWithInternalConstructor
{
public int Property { get; }
public TypeWithInternalConstructor Child { get; }
internal TypeWithInternalConstructor(int property, TypeWithInternalConstructor child)
{
Property = property;
Child = child;
}
}
The code is based on #alex-povar answer in this SO thread.
When I debug the AutoFixture sources it seems that when the constructor parameters are being resolved that for the child constructor parameter an OmitSpecimen is resolved.
By the way the same exception occurs when the recursion depth is set to 1.
How can I tell AutoFixture to create an instance of a type with an internal constructor that has a self referencing parameter type in the constructor?

Related

How to call non-generic methods inside generic types using reflection

Using .Net Framework 4.8.
I'm creating a shortcut system for my MDI WinForms application, so you can invoke methods when you press certain keys on certain forms, using custom attributes.
For context, the attributes look like this, and save them as Shortcutentry:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public sealed class ShortcutMethodAttribute : Attribute
{
public Keys[] Combination {get; set;}
public ShortcutMethodAttribute(params Keys[] combination)
{
Combination = combination;
}
}
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class)]
public sealed class ShortcutTypeAttribute : Attribute
{
}
public class ShortcutEntry
{
public ShortcutMethodAttribute Attribute { get; private set; }
public object Object { get; set; }
public Keys[] KeyCombination { get; set; }
public MethodInfo MethodInfo { get; private set; }
public ShortcutEntry(object #object, Keys[] keyCombination, MethodInfo methodInfo, ShortcutMethodAttribute attrib)
{
this.Object = #object;
this.KeyCombination = keyCombination;
this.MethodInfo = methodInfo;
this.Attribute = attrib;
}
public void Trigger()
{
MethodInfo.Invoke(Object, null);
}
}
I resolve all shortcuts like this and save them as a Dictionary<Type, ShortcutEntry>:
public Dictionary<Type, List<ShortcutEntry>> RegisterAllAssemblyShortcuts()
{
var shortcuts = new Dictionary<Type, ShortcutEntry>();
var types = Assembly.GetExecutingAssembly().GetTypes();
var typesWithAttribute = types.Where(x => x.GetCustomAttributes<ShortcutTypeAttribute>(false).Any());
foreach (var type in typesWithAttribute)
{
var methods = type.GetMethods().Where(x => x.GetCustomAttributes(typeof(ShortcutMethodAttribute), false).Length > 0);
foreach (var method in methods)
{
var attributes = method.GetCustomAttributes(typeof(ShortcutMethodAttribute), false).OfType<ShortcutMethodAttribute>();
if (attributes == null) continue;
foreach (var attribute in attributes)
{
var se = new ShortcutEntry(
null,
attribute.KeyCombination,
method,
attribute
);
if (!shortcuts.ContainsKey(type)) shortcuts.Add(type, new List<ShortcutEntry>);
shortcuts[type].Add(se);
}
}
}
return shortcuts;
}
To use it, you need to assign the ShortcutTypeAttribute to a type, and then ShortcutMethodAttribute to the method you want to call, with the key combination passed as parameter.
[ShortcutTypeAttribute]
public class SomeClass
{
public void SomeMethodA()
{
// do something
}
[ShortcutMethodAttribute(Keys.O, keys.I)]
public void SomeMethodB()
{
// do something
}
}
To summarize, it works like this:
Add ShortcutTypeAttribute to type containing the methods you want to call.
Add ShortcutMethodAttribute to the method to be called (with key combination).
Call RegisterAllAssemblyShortcuts()
Determine the type of the active MDI form.
Listen for keyboard input and check if shortcuts[mdiType] has any match.
If there is a ShortcutEntry then assing the Object and call ShortcutEntry.Trigger().
All of this steps work fine
The problem arises when I try to call a non-generic method with ShortcutEntry.Trigger() that is declared on a generic type, like so:
[ShortcutTypeAttribute]
public class KeyboundForm<T> : Form where T : class
{
[ShortcutMethodAttribute(Keys.O)]
public virtual void KeyOPressed() {}
}
The exception I get is:
System.InvalidOperationException: 'Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.'
I don't know why the MethodInfo for KeyOPressed() has MethodInfo.ContainsGenericParameters = true, when:
MethodInfo.IsGenericMethod = false
MethodInfo.IsGenericMethodDefinition = false
So I can't call MakeGenericMethod() on the KeyOPressed's MethodInfo
How can I invoke a non-generic method in a generic type?
Answer Edit: now it's working
Replaced the Trigger Function to recalculate methodinfo when it was generic.
public void Trigger()
{
if (MethodInfo.ContainsGenericParameters)
{
var type = Object.GetType();
var methodinfo = type.GetMethod(MethodInfo.Name);
methodinfo.Invoke(Object, null);
}
else
{
MethodInfo.Invoke(Object, null);
}
}
I don't know why the MethodInfo for KeyOPressed() has MethodInfo.ContainsGenericParameters == true`, when ...
This is because KeyOPressed is declared in a generic type. You need to create bound generic type (i.e. KeyboundForm<SomeActualForm>) to be able to invoke it.
One approach is to change your reflection to support only bound generic types:
var typesWithAttribute = types
.Where(t => !t.ContainsGenericParameters)
.Where(x => x.GetCustomAttributes<ShortcutTypeAttribute>(false).Any())
Which will capture non-generic types like SomeClass and bound generic types like SomeOtherClass : KeyboundForm<SomeFormType> marked with corresponding attribute.
Or check for inherited attributes (GetCustomAttributes<ShortcutTypeAttribute>(true)) for classes which are bound generic types (Type.IsConstructedGenericType == true).
Related:
Invoke a non generic method with generic arguments defined in a generic class

Find out if class implements an interface thru reflection

I have the following class in c#:
public class WorkOrderStatus : ICustomEnum<WorkOrderStatus>
{
}
during runtime I need to figure out if a property of the following class implements the custom interface.
public class WorkOrder{
public WorkOrderStatus Status {get;set;}
}
So I tried to do the following(using reflection to figure it out):
prop.PropertyType.GetInterfaces().Contains(typeof(ICustomEnum));
But this says that ICustomEnum requires a generic type. So i Tried to do the following, but it doesnt work:
var type = prop.GetType();
prop.PropertyType.GetInterfaces().Contains(typeof(ICustomEnum<typeof(type)>));
saying type is a variable but used like a type
[Edit 1]
I later need to be able to create an instance of WorkOrderStatus or any other class that implements this interface thru reflection like this:
var instance = (ICustomEnum<WorkOrderStatus|SomeOtherStatus...>)Activator.CreateInstance(prop.PropertyType);
It's quite simple to do with IsAssignableTo:
Type propertyType = typeof(WorkOrder).GetProperty("Status").PropertyType;
Type interfaceType = typeof(ICustomEnum<>).MakeGenericType(propertyType);
bool implements = propertyType.IsAssignableTo(interfaceType);
And, you might find that typeof(ICustomEnum<>).MakeGenericType(propertyType); solves your problem in your code directly.
So instead of typeof(ICustomEnum<typeof(type)>) you write typeof(ICustomEnum<>).MakeGenericType(type).
Here's how you would use reflection to call a method so that you can move from run-time types back to compile-time types.
void Main()
{
Type propertyType = typeof(WorkOrder).GetProperty("Status").PropertyType;
Type interfaceType = typeof(ICustomEnum<>).MakeGenericType(propertyType);
bool implements = propertyType.IsAssignableTo(interfaceType);
if (implements)
{
object propertyInstance = Activator.CreateInstance(propertyType);
var method =
this
.GetType()
.GetMethod("SomeMethod", BindingFlags.Instance | BindingFlags.NonPublic)
.MakeGenericMethod(propertyType);
method.Invoke(this, new[] { propertyInstance });
}
}
private void SomeMethod<T>(ICustomEnum<T> customEnum)
{
Console.WriteLine($"Success with {typeof(T)}");
}
That outputs the following:
Success with WorkOrderStatus
Here's the sundry code you need to run the above:
public class WorkOrderStatus : ICustomEnum<WorkOrderStatus> { }
public interface ICustomEnum<T> { }
public class WorkOrder
{
public WorkOrderStatus Status { get; set; }
}
You could use GetGenericTypeDefinition for this purpose. For example,
propertyInfo.PropertyType
.GetInterfaces()
.Where(x => x.IsGenericType)
.Any(i => i.GetGenericTypeDefinition() == typeof(ICustomEnum<>));
To retrieve all properties of the Type which implements the particular generic interface, you could
var properties = typeof(WorkOrder).GetProperties();
var result = properties.Where(property=>property.PropertyType
.GetInterfaces()
.Where(x => x.IsGenericType)
.Any(i => i.GetGenericTypeDefinition() == typeof(ICustomEnum<>)));

Set constructor parameter type for structuremap Registry

This is the follow up question to thread: How to pass parent/child class as constructor parameter with structuremap?
Thanks PHeiberg. Really helps. Got another two questions:
Why do we need PricingHandlerFactory constructor there?
What it frustrate me is that actually PricingHandler is not invoked directly, we are using reflection and Registry to find PricingHandler. i.e.(Not all codes are pasted.)
public class MessageHandlerRegistry : Registry
{
public MessageHandlerRegistry()
{
Scan(x =>
{
x.AssemblyContainingType(typeof(PricingHandler));
x.ConnectImplementationsToTypesClosing(typeof(IMessageHandler<>));
});
}
}
private object QueryHandlerExecute(IMessage message)
{
var handlerType = typeof(IMessageHandler<>);
var genericType = handlerType.MakeGenericType(message.GetType());
var messageHandler = ObjectFactory.GetInstance(genericType);
return messageHandler.GetType().GetMethod("Execute")
.Invoke(messageHandler, new object[] { message });
}
The actual declaration of PricingHandler is:
public class PricingHandler : IMessageHandler<PricingMessage>
{
public PricingHandler(IPricingFactorsRepository pricingFactorsRepository)
public object Execute(PricingMessage pricingMsg){}
}
Simply speaking, we find PricingHandler by IMessageHandler<PricingMessage>. So we can't use
ObjectFactory.GetInstance<PricingHandler>();
to find PricingHandler and set the type of constructor parameter.
So, in such case, how can we set the constructor parameter type?
Edit1.
For now, I am updating the 'FACTORY' class to allow specifying named instance(pricinghandler.)
private object QueryHandlerExecute(IMessage message,string instanceName)
{
var handlerType = typeof(IMessageHandler<>);
var genericType = handlerType.MakeGenericType(message.GetType());
var messageHandler = string.IsNullOrEmpty(instanceName)
? ObjectFactory.GetInstance(genericType)
: ObjectFactory.GetNamedInstance(genericType, instanceName);
return messageHandler.GetType().GetMethod("Execute").Invoke(messageHandler, new object[] { message });
}

Casting generic type instances created using Reflection

I'm creating instances of a generic type using reflection:
public interface IModelBuilder<TModel>
{
TModel BuildModel();
}
public class MyModel
{
public string Name { get; set; }
}
public class MyModelBuilder : IModelBuilder<MyModel>
{
public MyModel BuildModel()
{
throw new NotImplementedException();
}
}
At runtime all we know is the Type of model e.g. MyModel. I can find instances of the relevant model builder like so:
var modelBuilders = from t in Assembly.GetExecutingAssembly().GetTypes()
from i in t.GetInterfaces()
where i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(IModelBuilder<>)
&& i.GetGenericArguments()[0] == modelType
select t;
var builder = Activator.CreateInstance(modelBuilders.First());
But I'm not sure how I can then cast the instance as IModelBuilder<TModel> so I can call and work with the result of BuildModel().
Since modelType is just a Type instance, you can't do that automatically, since there is no non-generic API available. Various options:
1: use reflection, for example (untested)
object builder = Activator.CreateInstance(...);
var model=builder.GetType().GetMethod("BuildModel").Invoke(builder,null);
2: cheat with dynamic:
dynamic builder = Activator.CreateInstance(...);
var model = builder.BuildModel();
3: make a non-generic version of IModelBuilder, and use that
Note that 1 & 2 rely on a public implementation of the interface, and will fail for a (perfectly legal) explicit interface implementation. For "1", you can fix this via:
var model = typeof(IModelBuilder<>).MakeGenericType(modelType)
.GetMethod("BuildModel").Invoke(builder);
A final sneaky option is to flip from a non-generic method into a generic method, so inside the generic method you can use all the members directly. There's a lazy way to do that via dynamic:
interface ISneaky<T>
{
T Foo { get; }
}
class Sneaky<T> : ISneaky<T>
{
T ISneaky<T>.Foo { get { return default(T); } }
}
class Program
{
static void Main()
{
Execute(typeof(int));
}
static void Execute(Type t)
{
dynamic obj = Activator.CreateInstance(
typeof(Sneaky<>).MakeGenericType(t));
// crafy hack to flip from non-generic code into generic code:
Evil(obj);
}
static void Evil<T>(ISneaky<T> sneaky)
{ // in here, life is simple; no more reflection
Console.WriteLine("{0}: {1}", typeof(T).Name, sneaky.Foo);
}
}

Is there a way to deal with unknown generic types?

I have this code
public interface IConsumable<T> {
void Consume(T item);
}
public interface IProducer<T> {
IConsumable<T> Consumer { get; set; }
void Produce();
}
public class MyClass : MyType,
IConsumable<ISpecifcItem>
{
public void Consume(ISpecificItem item) { ... }
}
public class MySpecificItemProducer
: IProducer<ISpecificItem> {
public IConsumable<ISpecificItem> Consumer { get; set; }
public void Produce() {
ISpecificItem myItem = new MyVerySpecificItem();
Consumer.Consume(myItem);
}
}
Then I'm having a controller that takes any MyType, discovers all types of IConsumable<> that it implements and gets the type of the generic type parameter. With this list of types it discovers all producers that implement IProducer<TParam>. That's not difficult:
var consumerTypes =
myType.GetType().GetInterfaces()
.Where(x => x.IsGenericType)
.Where(x => x.GetGenericTypeDefinition() ==
typeof(IConsumable<>));
if (consumerTypes.Any()) {
var instanceTypes = consumerTypes
.Select(x => x.GetGenericArguments().First())
.Select(x => typeof(IProducer<>).MakeGenericType(x));
// for each of those types discover classes where
// it assignable from
// and instantiate the class using the Activator
}
But the problem is, how do I set the Consumer property of the producer? The producer instance is an object to me, I can't cast it to an IProducer<T>, because I can't use T like a variable.
I can do it with reflection producerInstance.GetType().GetProperty("Consumer").SetValue(producerInstance, consumerInstance, null); but I wanted to know if there's another way?
Interestingly, this failed at runtime:
MyClass consumerInstance;
dynamic test = producerInstance;
test.Consumer = consumerInstance;
It complained that the type of consumerInstance was incompatible to the type of the property.
EDIT: The dynamic example worked only when consumerInstance was also a dynamic, e.g.:
dynamic testC = consumerInstance;
dynamic testP = producerInstance;
testP.Consumer = testC;
Unfortunately, without refactoring the code you provided, you cannot solve the problem without more reflection (as you have done). However, you could use reflection before you set the consumer property if it makes it more readable for you.
var method = GetType().GetMethod("Process");
var genericType = interfaceType.GetGenericArguments().First();
var invocable = method.MakeGenericMethod(genericType);
invocable.Invoke(this, new object[] { producer, consumer });
public void Process<T>(IProducer<T> producer, IConsumable<T> consumer)
{
producer.Consumer = consumer;
}
Are you giving >1 IConsumable to MyType and just altering the generic type argument? I assume you are because you get a list of those interfaces. I don't know where you get your producers from, but the only way to not use reflection is to stay out of it. You could consider forcing each 'MyType' to provide a method that would 'setup' a list of producers (MyType internally would know all of it's own consumable types). Depending on where you pull the producers from (internal to MyType or external) you may have to do the following:
public interface IProducer { }
public interface IProducer<T> : IProducer
{
IConsumable<T> Consumer { get; set; }
void Produce();
}
public interface IConsumableProvider
{
void SetupProducers(params IProducer[] producers);
}
public class MyType :
IConsumable<int>,
IConsumable<double>,
IConsumableProvider
{
public void Consume(int item)
{
throw new NotImplementedException();
}
public void Consume(double item)
{
throw new NotImplementedException();
}
public void SetupProducers(params IProducer[] producers)
{
(producers[0] as IProducer<int>).Consumer = (this as IConsumable<int>);
(producers[1] as IProducer<double>).Consumer = (this as IConsumable<double>);
}
}
I'm not in love with the solution, but I feel an optimal solution would require more information about your current code base - else I would give an answer too divergent to what you already have.

Categories