Unity container, resolve to an abstract class level and not top Interface - c#

I have the following code defined in terms of hierarchy -
public interface ISomeInterface
{
bool DoSomething();
}
public abstract class AbsActualWorker : ISomeInterface
{
public bool DoSomething()
{
Console.WriteLine("DoSomething");
throw new Exception("throwing exception for the sake of it!");
}
public abstract bool DoSomething2();
}
public class ActualWorker : AbsActualWorker
{
public override bool DoSomething2()
{
Console.WriteLine("DoSomething2");
Thread.Sleep(1000);
return true;
//throw new Exception("throwing exception for the sake of it!");
}
}
Im trying to resolve to the ActualWorker level and execute its DoSomething2
var container = new UnityContainer();
container.AddNewExtension<Interception>();
container.RegisterType<AbsActualWorker, ActualWorker>();
container
.RegisterType<ISomeInterface, ActualWorker>(new Interceptor(new InterfaceInterceptor()),
new InterceptionBehavior(new MyLoggerBehavior())
);
var instance = container.Resolve<ISomeInterface>();
if (instance != null)
{
instance.DoSomething();
}
Code happily resolves and can call
instance.DoSomething();
When I cast instance to ActualWorker Im getting null. Id like to use call DoSomething2.
public class MyLoggerBehavior : IInterceptionBehavior
{
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
var returnValue = getNext()(input, getNext);
if (returnValue.Exception != null)
{
Console.WriteLine("Exception occurred!!");
}
else
{
Console.WriteLine("Method {0} returned {1}", input.MethodBase, returnValue.ReturnValue);
}
return returnValue;
}
public IEnumerable<Type> GetRequiredInterfaces()
{
return Type.EmptyTypes;
}
public bool WillExecute
{
get { return true; }
}
}

Your problem is in interceptor. Due to
container.RegisterType<ISomeInterface, ActualWorker>(new Interceptor(new InterfaceInterceptor()), new InterceptionBehavior(new MyLoggerBehavior()));
You get for ISomeInterface not ActualWorker type but a wrappertype that realize ISomeInterface. This type cannot be casted to ActualWorker.
If you work with Dependency injection you should not call methods that is not in public interface that you inject. If you need to cast variable of interface to concrete realization it means that you do something wrong.

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}'");
}
}

Call a generic method ensuring where

I have a generic method, on the base of T type I need to call a stricter generic method, how can I do it without reflections? In the example I used as that is obviusly wrong
public T foo1<T>()
{
if(T is IMyInterface)
{
return SpecificMethod<T as IMyInterface>();
}
}
private T SpecificMethod<T>() where T : IMyInterface
{
// IMyInterface specific implementation
}
private T GenericMethod<T>()
{
// something generic to do
}
You can approach it this way:
public interface IMyInterface { }
public T Foo1<T>()
{
if (typeof(T) == typeof(IMyInterface))
{
return (T)SpecificMethod<IMyInterface>();
}
return default(T);
}
private T SpecificMethod<T>() where T : IMyInterface
{
return default(T);
}
private T GenericMethod<T>()
{
return default(T);
}
What you asked for, can't just be done.

How can I create a specific object type at runtime?

I have an interface that is implemented by all of my classes which are responsible for exporting data to different formats.
Sample code:
public interface IExport
{
string Exporter();
}
public class ExcelExport : IExport
{
public string Exporter()
{
return "excel";
}
}
public class PdfExport : IExport
{
public string Exporter()
{
return "pdf";
}
}
I want to get a specific type in runtime, so I know I have to use abstract factory, but don't I know how tp in this example.
Exports are handled by the manager class:
public interface IExportManager
{
IExport GetExportProvider(ExportType type);
}
public interface IExportFactory
{
IExport CreateExport(ExportType type);
}
public class ExportManager : IExportManager
{
private IExportFactory exportFactory;
public ExportManager(IExportFactory exportFactory)
{
this.exportFactory = exportFactory;
}
public IExport GetExportProvider(ExportType type)
{
return exportFactory.CreateExport(type);
}
}
public enum ExportType
{
PDF,
XLSX
}
How can I get the right object instance depending on the type parameter using the GetExportProvider methods?
This is my Ninject module:
public class NinModule : NinjectModule
{
public override void Load()
{
this.Bind<IExportFactory>().ToFactory();
this.Bind<IExportManager>().To<ExportManager>();
this.Bind<IExport>().To<ExcelExport>();//.WhenInjectedInto<IExportManager>().WithPropertyValue("type", ExportType.XLSX);
this.Bind<IExport>().To<PdfExport>();//.WhenInjectedInto<IExportManager>().WithPropertyValue("type", ExportType.PDF);
}
}
And the code used to test it:
static void Main(string[] args)
{
IKernel k = new StandardKernel(new NinModule());
IExportManager r = k.Get<IExportManager>();
var pdf = r.GetExportProvider(ExportType.PDF);
Console.WriteLine(pdf.Exporter());
Console.Read();
}
Thanks in advance for your help.
I don't know anything about Ninject, but strictly from a C# perspective, why wouldn't this work...
public class ExportFactory : IExportFactory
{
public IExport CreateExport(ExportType type)
{
switch(type)
{
case ExportType.PDF:
return new PdfExport();
case ExportType.XLSX
return new ExcelExport();
}
}
}
I think you need to create dynamic binding in ExportFactory class.
Something like this:
if (exportType == ExportType.PDF)
{
Bind<IExport>().To<PdfExport>().InRequestScope();
}
else if (exportType == ExportType.XLSX)
{
Bind<IExport>().To<ExcelExport>().InRequestScope();
}
Alright, finally I got the solution.
One possibility is to create a custom provider:
public class ExportProvider : Provider<IExport>
{
protected override IExport CreateInstance(IContext context)
{
ExportType type = (ExportType)context.Parameters.First().GetValue(context, null);
switch (type)
{
case ExportType.PDF: return new PdfExport();
case ExportType.XLSX: return new ExcelExport();
}
return null;
}
}
And config: this.Bind<IExport>().ToProvider<ExportProvider>();
Second possibility I have found:
this.Bind<IExport>().To<ExcelExport>().When((q) =>
{
ExportType type = (ExportType)q.Parameters.First().GetValue(new DummyContext(), null);
return type == ExportType.XLSX;
});
this.Bind<IExport>().To<PdfExport>().When((q) =>
{
ExportType type = (ExportType)q.Parameters.First().GetValue(new DummyContext(), null);
return type == ExportType.PDF;
});
The GetValue of IParameter requires not null IContext provided. In the When clause we can't get any, but we can use diffrent one, because this parameter is not checked in the method as it look like. So we can create a simple class that implements the IContext interface:
public class DummyContext : IContext
{
public Ninject.Planning.Bindings.IBinding Binding
{
get { throw new NotImplementedException(); }
}
public Type[] GenericArguments
{
get { throw new NotImplementedException(); }
}
public IProvider GetProvider()
{
throw new NotImplementedException();
}
public object GetScope()
{
throw new NotImplementedException();
}
public bool HasInferredGenericArguments
{
get { throw new NotImplementedException(); }
}
public IKernel Kernel
{
get { throw new NotImplementedException(); }
}
public ICollection<IParameter> Parameters
{
get { throw new NotImplementedException(); }
}
public Ninject.Planning.IPlan Plan
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
public IRequest Request
{
get { throw new NotImplementedException(); }
}
public object Resolve()
{
throw new NotImplementedException();
}
}

How to conditionally cast to multiple types in c#

I'm looking at a function with this pattern:
if( obj is SpecificClass1 )
{
((SpecificClass1)obj).SomeMethod1();
}
else if( obj is SpecificClass2 )
{
((SpecificClass2)obj).SomeMethod2();
}
else if( obj is SpecificClass3 )
{
((SpecificClass3)obj).SomeMethod3();
}
and get a code analysis warning: CA1800 Do not cast unnecessarily.
What's a good code pattern I can use to replace this code with that will be performant and concise.
Update
I didn't say, but obj is declared with type object.
I originally asked two questions here. I've split one off (which nobody had yet answered anyway): Why wouldn't the compiler optimize these two casts into one?
Interface
The best way would be to introduce an interface that all the types implement. This is only possible if the signatures match (or you don't have too many differences).
Using as
If creating an interface is not an option, you can get rid of the CA message by using the following pattern (though this also introduces unnecessary casts and therefore degrades performance a bit):
var specClass1 = obj as SpecificClass1;
var specClass2 = obj as SpecificClass2;
var specClass3 = obj as SpecificClass3;
if(specClass1 != null)
specClass1.SomeMethod1();
else if(specClass2 != null)
specClass2.SomeMethod2();
else if(specClass3 != null)
specClass3.SomeMethod3();
You can also change it to this structure (from my point of view, the above is better in terms of readability):
var specClass1 = obj as SpecificClass1;
if (specClass1 != null)
specClass1.SomeMethod1();
else
{
var specClass2 = obj as SpecificClass2;
if (specClass2 != null)
specClass2.SomeMethod2();
else
{
var specClass3 = obj as SpecificClass3;
if (specClass3 != null)
specClass3.SomeMethod3();
}
}
Registering the types in a dictionary
Also, if you have many types that you want to check for, you can register them in a dictionary and check against the entries of the dictionary:
var methodRegistrations = new Dictionary<Type, Action<object> act>();
methodRegistrations.Add(typeof(SpecificClass1), x => ((SpecificClass1)x).SomeMethod1());
methodRegistrations.Add(typeof(SpecificClass2), x => ((SpecificClass2)x).SomeMethod2());
methodRegistrations.Add(typeof(SpecificClass3), x => ((SpecificClass3)x).SomeMethod3());
var registrationKey = (from x in methodRegistrations.Keys
where x.IsAssignableFrom(obj.GetType()).FirstOrDefault();
if (registrationKey != null)
{
var act = methodRegistrations[registrationKey];
act(obj);
}
Please note that the registrations are easily extendable and that you can also call methods with different arguments in the action.
To avoid the double casting you could do the following
var objClass1= obj as SpecificClass1;
if(objClass1!=null)
objClass1.SomeMethod1();
Regarding the pattern you could make all these classes implement a common interface and make your method receive the interface.
public void SomeMethod(ISpecificInterface specific)
{
specific.SomeMethod1();
}
Can you do something like this here?
interface IBaseInterface
{
void SomeMethod();
}
public class Implementer1:IBaseInterface
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
public class Implementer2 : IBaseInterface
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
public class Implementer3 : IBaseInterface
{
public void SomeMethod()
{
throw new NotImplementedException();
}
}
And then, in caller code:
IBaseInterface concrete = GetInstance();
concrete.SomeMethod();
and GetInstance would create class objects based on conditions.
Your classes can be inherite a ISomeMethodInterface like this:
public interface ISomeMethodInterface
{
void SomeMethod();
}
public class SpecificClass1 : ISomeMethodInterface
{
//some code
public void SomeMethod()
{
}
}
public class SpecificClass2 : ISomeMethodInterface
{
//some code
public void SomeMethod()
{
}
}
public class SpecificClass3 : ISomeMethodInterface
{
//some code
public void SomeMethod()
{
}
}
And in your call:
((ISomeMethodsInterface)obj).SomeMethod();
The most extensible solution would probably be inheriting the concrete class while implementing an interface with a SomeMethod implementation that calls the correct SomeMethodx method on the inherited class. That way, you'll keep the existing interface while still keeping the existing methods.
public interface ISomething {
void SomeMethod();
}
public SpecificClass1Wrapper : SpecificClass1, ISomething {
void SomeMethod() { SomeMethod1(); }
}
If the objects are wrapped in this way before they're stored in the object reference, a cast to ISomething and a call to SomeMethod() will replace your entire if/else combination.
If the object on the other hand comes from code you have no way of extending and terse but still clear is what you're going for, you could create a simple helper method;
private bool CallIfType<T>(object obj, Action<T> action) where T : class
{
var concrete = obj as T;
if (concrete == null)
return false;
action(concrete);
return true;
}
You can then write the calls as a simple expression;
var tmp = CallIfType<SpecificClass1>(obj, x => x.SomeMethod1()) ||
CallIfType<SpecificClass2>(obj, x => x.SomeMethod2()) ||
CallIfType<SpecificClass3>(obj, x => x.SomeMethod3());
if(tmp)
Console.WriteLine("One of the methods was called");
Ok, bit rough, but:
public class BaseClass{}
public class SubClass1 : BaseClass
{
public void SomeMethod1()
{
}
}
public class SubClass2 : BaseClass
{
public void SomeMethod2()
{
}
}
public class Class1
{
public Class1()
{
var test = new SubClass1();
var lookup = new Dictionary<Type, Action<object>>
{
{typeof (SubClass1), o => ((SubClass1) o).SomeMethod1() },
{typeof (SubClass2), o => ((SubClass2) o).SomeMethod2() }
};
//probably best to check the type exists in the dictionary first,
//maybe wrap up the execution into a class of it's own so it's abstracted away
lookup[test.GetType()](test);
}
}
How about writing a method
public static class ObjectExtensions
{
public static bool TryCast<T>(this object from, out T to) where T : class
{
to = from as T;
return to != null;
}
}
and using it:
SpecificClass1 sc1;
SpecificClass2 sc2;
SpecificClass3 sc3;
if( obj.TryCast(out sc1) )
{
sc1.SomeMethod1();
}
else if( obj.TryCast(out sc2) )
{
sc2.SomeMethod2();
}
else if( obj.TryCast(out sc3) )
{
sc3.SomeMethod3();
}
Not sure if I'm missing a goal, but here's an option that should work.
if( obj is SpecificClass1 sc1 )
{
sc1.SomeMethod1();
}
else if( obj is SpecificClass2 sc2 )
{
sc2.SomeMethod2();
}
else if( obj is SpecificClass3 sc3 )
{
sc3.SomeMethod3();
}
else
{
throw new exception();
}
You can also
switch (obj)
{
case SpecificClass1 sc1:
sc1.SomeMethod1();
break;
case SpecificClass2 sc1:
sc2.SomeMethod2();
break;
case SpecificClass3 sc1:
sc3.SomeMethod3();
break;
default:
throw new Exception();
}

Why can't I return my object as its' interface?

I have a series of interface definitions, all of which compile (so my objects are composed correctly). The objects instantiate, as expected. However, when I try to return the object from its' underlying factory I get the following error:
ERROR:
Unable to cast object of type
'SampleLibrary.Domain.DataAcessors.Person.SQLDataAccessor' to type
'Common.Contracts.DataAccessors.IDataAccessorModel`2[SampleLibrary.Contracts.Models.IPerson,SampleLibrary.Domain.DataAccessors.Types.SqlServer]'.
Please keep in mind I am trying to return each instance as the IDataAccessor interface.
CODE:
public interface IDataAccessor<I, T>
{
T AccessType { get; }
}
public interface IDataAccessorModel<I, T> : IDataAccessor<I, T>
{
I Instance { get; }
IResult<string> Get(I instance);
IResult<string> Add(I instance);
IResult<string> Update(I instance);
IResult<string> Delete(I instance);
}
public class SQLDataAccessor : IDataAccessorModel<IPerson, IAccessType>
{
internal SQLDataAccessor(IResult<string> result)
{
_connectionString = "";
_result = result;
}
private readonly string _connectionString;
private IResult<string> _result;
public IAccessType AccessType { get { return new SqlServer(); } }
public IPerson Instance { get; private set; }
public IResult<string> Add(IPerson instance)
{
Instance = instance;
return _result;
}
public IResult<string> Get(IPerson instance)
{
Instance = instance;
return _result;
}
public IResult<string> Delete(IPerson instance)
{
Instance = instance;
return _result;
}
public IResult<string> Update(IPerson instance)
{
Instance = instance;
return _result;
}
}
public class FactoryDataAccess : IFactoryDataAccess
{
internal FactoryDataAccess() { }
public IDataAccessor<I, T> Create<I, T>()
{
var model = typeof(I);
var target = typeof(T);
if (model.IsAssignableFrom(typeof(IPerson)))
{
if (target == typeof(SqlServer)) {
var accessor = new Person.SQLDataAccessor(new Result());
// This next line FAILS!
return (IDataAccessorModel<I, T>)accessor;
}
}
throw new NotSupportedException("Type " + target.FullName + " and Source " + model.FullName + " is not supported.");
}
}
UPDATE:
Please keep in mind that IDataAccessorModel can be used by any desired DataAccess type you wish to define.
SQLDataAccessor implements IDataAccessorModel<IPerson, IAccessType>, so it would work only if <I, T> were <IPerson, IAccessType>. There is no guarantee about that, since the method is generic and I and T could be any type, so the cast fails.
Of course, since you're checking the types of I and T, you know the cast would be valid, but the compiler doesn't. You can trick it like this:
return (IDataAccessorModel<I, T>)(object)accessor;
However, since T has to be SqlServer, it doesn't make sense to make it a generic type parameter. And since I has to implement IPerson, there should be a constraint on it. So the method signature should be:
public IDataAccessor<I, T> Create<T>() where T : IPerson
It work for me if I declare SQLDataAccessor like this:
public class SQLDataAccessor : IDataAccessorModel<IPerson, SqlServer>
{
...
}
You are probably calling it like this
var factory = new FactoryDataAccess();
var da = factory.Create<IPerson, SqlServer>();
i.e. you call it with T being SqlServer. If you declare T as IAccessType in SQLDataAccessor it is not guaranteed that IAccessType would be SqlServer. Therefore the casting error. (However, SqlServer is guaranteed to be IAccessType as it probably implements it.)
SQLDataAccessor is not a generic class, but implements IDataAccessorModel<IPerson, IAccessType> exactly, so your method Create should return IDataAccessor<IPerson, IAccessType>, but you probably called it with other generic types.
Change SqlDataAccessor to:
public class SQLDataAccessor<I, T> : IDataAccessorModel<I, T>
{
internal SQLDataAccessor(IResult<string> result)
{
_connectionString = "";
_result = result;
}
private readonly string _connectionString;
private IResult<string> _result;
public T AccessType { get { return new SqlServer(); } }
public I Instance { get; private set; }
public IResult<string> Add(I instance)
{
Instance = instance;
return _result;
}
public IResult<string> Get(I instance)
{
Instance = instance;
return _result;
}
public IResult<string> Delete(I instance)
{
Instance = instance;
return _result;
}
public IResult<string> Update(I instance)
{
Instance = instance;
return _result;
}
}
You might want to limit I and T to the interfaces, so add a where constraint:
public class SQLDataAccessor<I, T> : IDataAccessorModel<I, T>
where I : IPerson
where T : IAccessType
The way you have it, I could be any type derived from IPerson and T is exactly of type SqlServer, which would cause the cast to fail since SQLDataAccessor implements the IDataAccessorModel with different parameters. You would need to have a more exact cast, such as:
return (IDataAccessorModel<IPerson, IAccessType>)accessor;

Categories

Resources