Why Func<T> is used in this code? - c#

One of my colleague came across this code and we are unable to understand why _resolverThunk is needed.
Summary of the code looks like this:
private Func<IDependencyResolver> _resolverThunk;
public SingleServiceResolver()
{
_resolverThunk = () => DependencyResolver.Current;
}
private TService GetValueFromResolver()
{
TService result = _resolverThunk().GetService<TService>();
return result;
}

If you look at another internal constructor, it sets the _resolverThunk from parameter. So it makes sense.
internal SingleServiceResolver(Func<TService> staticAccessor, TService defaultValue, IDependencyResolver resolver, string callerMethodName)
: this(staticAccessor, defaultValue, callerMethodName)
{
if (resolver != null)
{
_resolverThunk = () => resolver;
}
}
Otherwise, there is no reason to do it.

Related

ServiceStack IContainerAdapter adapting Autofac 5.2.0 version

I'm trying to upgrade the latest Autofac package to 5.2.0, but not really successfully becasue of interface changes,
From (Autofac 4.9.4)
public static class ResolutionExtensions
{
public static bool TryResolve<T>(this IComponentContext context, out T instance);
}
To (Autofac 5.2.0)
public static class ResolutionExtensions
{
public static bool TryResolve<T>(this IComponentContext context, out T instance)
where T : class;
}
The ServiceStack package has a IContainerAdapter interface (ServiceStack.Interfaces 5.8.0)
public interface IResolver
{
T TryResolve<T>();
}
public interface IContainerAdapter : IResolver
{
T Resolve<T>();
}
My AutofacIocAdapter implementates this IContainerAdapter
public class AutofacIocAdapter : IContainerAdapter
{
public T TryResolve<T>()
{
if (m_Container.TryResolve<Autofac.ILifetimeScope>(out var scope) &&
scope.TryResolve<T>(out var scopeComponent))
{
return scopeComponent;
}
if (m_Container.TryResolve<T>(out var component))
{
return component;
}
return default(T);
}
}
But got compiling error after upgrading Autofac
Error CS0452 The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'ResolutionExtensions.TryResolve<T>(IComponentContext, out T?)'
Any suggestion to resolve ?
You wouldn't be able to call a class with a class constraint from a method without that constraint from C#, but you could use reflection to invoke it.
But your first attempt should be to bypass the API with the constraint. Looking at AutoFac's implementation of TryResolve will show what APIs they call internally:
public static bool TryResolve<T>(this IComponentContext context, out T? instance)
where T : class
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
object? component;
// Null annotation attributes only work if placed directly in an if statement.
if (context.TryResolve(typeof(T), out component))
{
instance = (T)component;
return true;
}
else
{
instance = default;
return false;
}
}
So you would just need to bypass their generic API with constraints and call the same runtime Type API that they call, something like:
public class AutofacIocAdapter : IContainerAdapter
{
private readonly Autofac.IContainer container;
public AutofacIocAdapter(Autofac.IContainer container) =>
this.container = container;
public T TryResolve<T>()
{
if (container.TryResolve<Autofac.ILifetimeScope>(out var scope) &&
scope.TryResolve(typeof(T), out var scopeComponent))
return (T)scopeComponent;
if (container.TryResolve(typeof(T), out var component))
return (T)component;
return default;
}
public T Resolve<T>()
{
var ret = TryResolve<T>();
return !ret.Equals(default)
? ret
: throw new Exception($"Error trying to resolve '{typeof(T).Name}'");
}
}

How can I obtain return type from method passed as an argument in another method with Roslyn?

Lets say that I have a code:
public class Test {
private readonly IFactory _factory;
private readonly ISomeClass _someClass;
public Test(IFactory factory, ISomeClass someClass)
{
_factory = factory;
_someClass = someClass;
}
....
public void TestMethod() {
_someClass.Do(_factory.CreateSomeObject());
}
}
public class Factory {
public SomeObject CreateSomeObject() {
return new SomeObject();
}
}
public class SomeClass {
public void Do(SomeObject obj){
....
}
}
I would like to get return type of CreateSomeObject from InvocationExpressionSyntax of someClass.Do(_factory.CreateSomeObject()); Is it possible?
I have a list of arguments (ArgumentSyntax) but I have no clue how to get method return type from ArgumentSyntax.
Is there better and easier way to do it other then scanning a solution for Factory class and analyzing CreateSomeObject method?
Yes, it is possible.
You would need to use Microsoft.CodeAnalysis.SemanticModel for it.
I assume you have CSharpCompilation and SyntaxTree already available, so you would go in your case with something like this:
SemanticModel model = compilation.GetSemanticModel(tree);
var methodSyntax = tree.GetRoot().DescendantNodes()
.OfType<MethodDeclarationSyntax>()
.FirstOrDefault(x => x.Identifier.Text == "TestMethod");
var memberAccessSyntax = methodSyntax.DescendantNodes()
.OfType<MemberAccessExpressionSyntax>()
.FirstOrDefault(x => x.Name.Identifier.Text == "CreateSomeObject");
var accessSymbol = model.GetSymbolInfo(memberAccessSyntax);
IMethodSymbol methodSymbol = (Microsoft.CodeAnalysis.IMethodSymbol)accessSymbol.Symbol;
ITypeSymbol returnType = methodSymbol.ReturnType;
Once you get the desired SyntaxNode out of the semantic model, you need to get its SymbolInfo and properly cast it, to get its ReturnType which does the trick.

How to ensure design-time checking using generics to instantiate objects in a factory?

Given the following code to return a new object implementing IValidateParameter:
public static IValidateParameter GetValidator<TClass, TParameterType>(TParameterType objectToValidate)
where TClass : IValidateParameter
{
return (TClass) Activator.CreateInstance(typeof(TClass), objectToValidate);
}
And, for instance, this concrete implementation:
public class DateRangeValidator : IValidateParameter
{
private readonly DateRange _dateRange;
private readonly Predicate<DateTime> _isNotMinValue = x => x != DateTime.MinValue;
private readonly Predicate<DateRange> _startIsBeforeEnd = x => x.Start < x.End;
public DateRangeValidator(DateRange dateRange)
{
_dateRange = dateRange;
}
public bool IsValid => _isNotMinValue(_dateRange.Start) &&
_isNotMinValue(_dateRange.End) &&
_startIsBeforeEnd(_dateRange);
}
Using above code, this will compile and run as desired since the parameter is of type DateRange, per the constructor signature.
var dateRangeCheck = ServiceFactory.GetValidator<DateRangeValidator, DateRange>(dateRange);
However, this shows no errors in VS2017 at design time but will fail since the parameter does not match the constructor signature.
var dateRangeCheck = ServiceFactory.GetValidator<DateRangeValidator, bool>(true);
How do I modify the generic method to get design-time type checking when the classes implementing IValidating all take different type objects as a parameter?
How about making your IValidateParameter a generic interface, with a type parameter that shows what data is validated?
public interface IValidateParameter<in T>
{
bool IsValid(T value);
}
Then your concrete implementation would be something like
public class DateRangeValidator : IValidateParameter<DateRange>
{
private readonly Predicate<DateTime> _isNotMinValue = x => x != DateTime.MinValue;
private readonly Predicate<DateRange> _startIsBeforeEnd = x => x.Start < x.End;
public bool IsValid(DateRange dateRange) =>
_isNotMinValue(dateRange.Start) &&
_isNotMinValue(dateRange.End) &&
_startIsBeforeEnd(dateRange);
}
Then your service factory would be
public class ServiceFactory
{
public static IValidateParameter<TParameterType> GetValidator<TClass, TParameterType>()
where TClass : IValidateParameter<TParameterType>
{
return (TClass)Activator.CreateInstance(typeof(TClass));
}
}
And you would use it like
var validator = ServiceFactory.GetValidator<DateRangeValidator, DateRange>();
var result = validator.IsValid(dateRange);

How to resolve named instances from LightCore ServiceLocator?

Lately I'm playing around a bit with the IoC tool LightCore. Since the last version no named instances are allowed anymore nontheless the ServiceLocator pattern is supported(?).
One of the crucial functionalities I need from the ServiceLocator is the resolving of named instances. My first idea was to override the DoGetInstance method and implement my own code.
My last workaround was to get a instance by it's typename
_testInstanceKey = "My.Namespace.MyType, MyAssembly";
IMyType type = locator.GetInstance(typeof(IMyType), _testInstanceKey)
protected override object DoGetInstance(Type serviceType, string key)
{
return _container.ResolveAll(serviceType)
.Where(x => x.GetType() == Type.GetType(key,true,true))
.FirstOrDefault();
}
This works out but what do I need a ServiceLocator for if I hardwire my typename?!
Has anybody any suggestions how I could work around this half-baked ServiceLocator?
You can solve this problem by introducing a IMyTypeFactory interface and letting the application take a dependency on that interface:
// Factory interface:
public interface IMyTypeFactory
{
IMyType GetByName(string name);
}
// Implementation in the composition root:
public class MyTypeFactory :
Dictionary<string, Func<IRequestHandler>>, IMyTypeFactory
{
public IMyType GetByName(string name) { return this[name](); }
}
// Registration
var factory = new MyTypeFactory
{
{ "foo", () => new MyType1() },
{ "bar", () => new MyType2() },
{ "boo", () => new MyType3() },
};
builder.Register<IMyTypeFactory>(c => factory);
As I said in the comments, try to move away from the use of the Service Locator anti-pattern. It will improve the testability and maintainability of your application. When using the dependency injection (DI) pattern, you don't call the container directly and there is no way to directly ask a named instance. When applying DI, you will have to change the way to configure the container or need to apply the right abstractions in your application (as shown with the IMyTypeFactory).
Assuming you can't change the way the framework calls the locator and assuming the framework uses the Common Service Locator is used as interface between your container and itself, you can add this functionality to a custom IServiceLocator implementation:
// This adapter wraps the CSL LightCoreAdapter of LightCore itself.
public class LightCoreServiceLocatorAdapter : IServiceLocator
{
private readonly LightCoreAdapter container;
public LightCoreServiceLocatorAdapter(IContainer container)
{
// You need a reference to LightCore.CommonServiceLocator.dll.
this.container = new LightCoreAdapter(container);
}
public IEnumerable<TService> GetAllInstances<TService>()
{
return this.container.GetAllInstances<TService>();
}
public IEnumerable<object> GetAllInstances(Type serviceType)
{
return this.container.GetAllInstances(serviceType);
}
public TService GetInstance<TService>(string key)
{
if (key == null)
{
return this.container.GetInstance<TService>(null);
}
else
{
// This is custom logic
this.container.GetInstance<INamedFactory<TService>>().GetByKey(key);
}
}
public TService GetInstance<TService>()
{
return this.container.GetInstance<TService>();
}
public object GetInstance(Type serviceType, string key)
{
if (key == null)
{
return this.container.GetInstance(serviceType);
}
else
{
// This is custom logic
var facType = typeof(INamedFactory<>).MakeGenericType(serviceType);
var factory = (INamedFactory)this.container.GetInstance(facType);
return factory.GetByKey(key);
}
}
public object GetInstance(Type serviceType)
{
return this.container.GetInstance(serviceType);
}
object IServiceProvider.GetService(Type serviceType)
{
((IServiceProvider)this.container).GetService(serviceType);
}
}
This class uses the following two custom interfaces:
public interface INamedFactory
{
object GetByKey(string key);
}
public interface INamedFactory<T> : INamedFactory
{
T GetByKey(string key);
}
Using this custom LightCoreServiceLocatorAdapter and these two custom interfaces, you can create custom factories, such as this generic one:
public sealed class NamedDelegateFactory<T> : INamedFactory<T>
{
private readonly Func<string, T> factory;
public NamedDelegateFactory(Func<string, T> factory)
{
this.factory = factory;
}
public T GetByKey(string key)
{
return this.factory(key);
}
object INamedFactory.GetByKey(string key)
{
return this.factory(key);
}
}
Which can be registered in the container as follows:
var factory = new NamedDelegateFactory<IMyType>(key =>
{
if (key == "Cool") return new MyType1();
else return new MyType2();
});
var builder = new ContainerBuilder();
builder.Register<INamedFactory<IMyType>>(c => factory);
Next, a LightCoreServiceLocatorAdapter can be created as follows:
var adapter = new LightCoreServiceLocatorAdapter(builder.Build());
Microsoft.Practices.ServiceLocation.ServiceLocator
.SetLocatorProvider(() => adapter);
You can register all named instances using the INamedFactory<T> interface and use the NamedDelegateFactory<T> wrapped with a delegate or implement a custom type that implements INamedFactory<T>.

Structuremap addalltypesof constructed by a specific constructor

I really like StructureMap as an IOC-framework especially the convention based registration. Now I try to do the following: I want to add all types that implement a specific interface when the class has a default (no parameters) constructor. And the types must be created using this constructor.
This is what I have untill now, which registers the correct types, but how do I specify that the default constructor should be used when creating an instance.
public class MyRegistry : Registry
{
public MyRegistry()
{
Scan(
x =>
{
x.AssemblyContainingType<IUseCase>();
x.Exclude(t => !HasDefaultConstructor(t));
x.AddAllTypesOf<IUseCase>();
});
}
private static bool HasDefaultConstructor(Type type)
{
var _constructors = type.GetConstructors();
return _constructors.Any(c => IsDefaultConstructor(c));
}
private static bool IsDefaultConstructor(ConstructorInfo constructor)
{
return !constructor.GetParameters().Any();
}
}
There are a few ways to force StructureMap to use a specific constructor. The simplest is to put the DefaultConstructor attribute on the constructor you want to use. Assuming you don't want to do that, you would have to create a custom RegistrationConvention.
public class UseCaseRegistrationConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
if (type.IsAbstract || type.IsInterface || type.IsEnum)
return;
var useCaseInterface = type.GetInterface("IUseCase");
if (useCaseInterface == null)
return;
var constructor = type.GetConstructors().FirstOrDefault(c => !c.GetParameters().Any());
if (constructor != null)
{
registry.For(useCaseInterface).Add(c => constructor.Invoke(new object[0]));
}
}
}
Then use it in your Scan call:
Scan(x =>
{
x.AssemblyContainingType<IUseCase>();
x.With(new UseCaseRegistrationConvention());
});

Categories

Resources