Got some vegetables going on:
public interface IVegetable
{
}
public class Potato : IVegetable
{
}
public class Onion : IVegetable
{
}
We'd focus on the onion and process it: I have single generic interface for a generic vegetable processor and one onion-specific:
public interface IVegetableProcessor<T> where T : IVegetable
{
string GetColor(T vegetable);
}
public interface IOnionProcessor : IVegetableProcessor<Onion>
{
void MakeCry(Onion onion);
}
public class OnionProcessor : IOnionProcessor
{
public string GetColor(Onion onion)
{
return "Purple";
}
public void MakeCry(Onion onion)
{
Console.WriteLine($"{onion} made you cry!");
}
}
As well as a generic factory:
interface IVegetableProcessorFactory
{
IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable;
}
internal class VegetableProcessorFactory : IVegetableProcessorFactory
{
public IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable
{
object processor = vegetable switch
{
Onion => new OnionProcessor(),
_ => throw new NotImplementedException($"Other vegetables not here yet")
};
return (IVegetableProcessor<T>)processor; //this will fail later
}
}
And finally this does not work:
static void Main(string[] args)
{
var onion = new Onion() as IVegetable;
var factory = new VegetableProcessorFactory();
var processor = factory.GetVegetableProcessor(onion);
Console.WriteLine(processor.GetColor(onion));
Console.ReadLine();
}
The error is:
System.InvalidCastException: 'Unable to cast object of type 'OnionProcessor' to type 'IVegetableProcessor`1[Vegetables.Program+IVegetable]'.'
How to make it understand the underlying class of IVegetable and cast the processor to it's corresponding type?
Your input is already contravariant, but by casting your Onion instance to IVegetable, it is no longer able to be cast back to IVetetableProcessor<T> in your factory, because at that point you need IVetetableProcessor<Onion>, but what you have is a IVegetableProcessor<IVegetable>, and your interface is not covariant.
By simply removing your initial cast of new Onion to IVegetable, your code works as is:
static void Main(string[] args)
{
var onion = new Onion();
var factory = new VegetableProcessorFactory();
var processor = factory.GetVegetableProcessor(onion);
Console.WriteLine(processor.GetColor(onion));
Console.ReadLine();
}
public interface IVegetable { }
public class Potato : IVegetable { }
public class Onion : IVegetable { }
public interface IVegetableProcessor<T> where T : IVegetable
{
string GetColor(T vegetable);
}
public interface IOnionProcessor : IVegetableProcessor<Onion>
{
void MakeCry();
}
public class OnionProcessor : IOnionProcessor
{
public string GetColor(Onion vegetable)
{
return "Purple";
}
public void MakeCry()
{
Console.WriteLine("You cry now!");
}
}
interface IVegetableProcessorFactory
{
IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable;
}
internal class VegetableProcessorFactory : IVegetableProcessorFactory
{
public IVegetableProcessor<T> GetVegetableProcessor<T>(T vegetable) where T : IVegetable
{
var processor = vegetable switch
{
Onion => new OnionProcessor(),
_ => throw new NotImplementedException($"Other vegetables not here yet")
};
return (IVegetableProcessor<T>)processor;
}
}
The fact that you have to cast in the first place is your hint that something is broken in your composition. As Selvin mentioned in the comments, implementing IVegetableProcessor<Onion> is NOT the same thing as implementing IVegetableProcessor<IVegetable>.
Your processor interfaces should implement IVegetableProcessor<IVegetable> and take IVegetable instances, allowing contravariance for the input parameters:
public interface IVegetableProcessor<T> where T : IVegetable
{
string GetColor(T vegetable);
}
public interface IOnionProcessor : IVegetableProcessor<IVegetable>
{
void MakeCry();
}
public class OnionProcessor : IOnionProcessor
{
public string GetColor(IVegetable vegetable)
{
return "Purple";
}
public void MakeCry()
{
Console.WriteLine("You cry now!");
}
}
interface IVegetableProcessorFactory
{
IVegetableProcessor<IVegetable> GetVegetableProcessor(IVegetable vegetable);
}
internal class VegetableProcessorFactory : IVegetableProcessorFactory
{
public IVegetableProcessor<IVegetable> GetVegetableProcessor(IVegetable vegetable)
{
var processor = vegetable switch
{
Onion => new OnionProcessor(),
_ => throw new NotImplementedException($"Other vegetables not here yet")
};
return processor;
}
}
This correctly outputs "Purple" when run via:
static void Main(string[] args)
{
var onion = new Onion();
var factory = new VegetableProcessorFactory();
var processor = factory.GetVegetableProcessor(onion);
Console.WriteLine(processor.GetColor(onion));
Console.ReadLine();
}
Related
could someone please help with the best way of returning the concrete implementation in the following scenarios. Say I have:
public interface IThing<TInput> where TInput : RequestBase
{
string Process(T input);
}
And then multiple implementations:
public class Thing1<T> : IThing<T> where T : ReqThing1
public class Thing2<T> : IThing<T> where T : ReqThing2
In my calling class what is the best way of wrapping the construction of those classes and returning the IThing that I want in a clean, testable way? Thanks
I don't quite understand what you want, but here's an idea:
public abstract class RequestBase
{
}
public class ReqThing1 : RequestBase
{
}
public class ReqThing2 : RequestBase
{
}
public interface IThing<T> where T : RequestBase
{
string Process(T input);
}
public class Thing1 : IThing<ReqThing1>
{
public string Process(ReqThing1 input)
{
throw new System.NotImplementedException();
}
}
public class Thing2 : IThing<ReqThing2>
{
public string Process(ReqThing2 input)
{
throw new System.NotImplementedException();
}
}
public class Program
{
public static void Main(string[] args)
{
var thing1 = new Thing1();
var thing2 = new Thing2();
}
}
I'm not sure if this is possible, I've seen some other posts asking similar question but none have a satisfactory answer.
What I want to do is resolve a collection of interfaces with differing generic types from Autofac. So constructor of class would look something like this:
public class SomeClass<T> where T : class
{
private readonly IEnumerable<ITestInterface<T>> _testInterfaces;
public SomeClass(IEnumerable<ITestInterface<T>> testInterfaces)
{
_testInterfaces = testInterfaces;
}
}
Ideally, I'd just like to be able to register each instance individually like so:
builder
.RegisterType<ImplementationA>()
.As<ITestInterface<A>>();
builder
.RegisterType<ImplementationB>()
.As<ITestInterface<B>>();
I've tried various combinations of RegisterGeneric etc but the Enumerable just keeps coming through empty.
Any help would be appreciated.
I was able to resolve this after playing with inheritance & generic constraints. The solution I ended up with looks like this:
Base classes / interfaces:
public abstract class BaseClass
{
public abstract string IAM { get; }
}
public interface ITestInterface<out T> where T : BaseClass
{
T GetSomething();
}
Implemented classes:
public class A : BaseClass
{
public override string IAM => "I AM TYPE A";
}
public class AInterface : ITestInterface<A>
{
public A GetSomething()
{
return new A();
}
}
public class B : BaseClass
{
public override string IAM => "I AM TYPE B";
}
public class BInterface : ITestInterface<B>
{
public B GetSomething()
{
return new B();
}
}
Class we want to resolve:
public interface ISomeClass
{
void DoSomething();
}
public class SomeClass<T> : ISomeClass where T : BaseClass
{
private readonly IEnumerable<ITestInterface<T>> _testInterfaces;
public SomeClass(IEnumerable<ITestInterface<T>> testInterfaces)
{
_testInterfaces = testInterfaces;
}
public void DoSomething()
{
foreach (var t in _testInterfaces)
{
var something = t.GetSomething();
Console.WriteLine(something.IAM);
}
}
}
And finally, Autofac configuration:
var builder = new ContainerBuilder();
builder
.RegisterType<SomeClass<BaseClass>>()
.AsSelf();
builder
.RegisterType<AInterface>()
.As<ITestInterface<BaseClass>>();
builder
.RegisterType<BInterface>()
.As<ITestInterface<BaseClass>>();
builder
.RegisterType<SomeClass<BaseClass>>()
.As<ISomeClass>();
var container = builder.Build();
var x = container.Resolve<ISomeClass>();
x.DoSomething();
Outputs:
I AM TYPE A
I AM TYPE B
Hope this helps someone in the future.
RegisterGeneric should work fine :
builder.RegisterType<TestImplementationA>()
.As<ITestInterface<A>>();
builder.RegisterType<TestImplementationB>()
.As<ITestInterface<B>>();
builder.RegisterGeneric(typeof(SomeClass<>))
.As(typeof(ISomeClass<>));
or
builder.RegisterType<TestImplementationA>()
.As<ITestInterface<A>>();
builder.RegisterType<TestImplementationB>()
.As<ITestInterface<B>>();
builder.RegisterGeneric(typeof(SomeClass<>))
.AsSelf();
You will find below a working sample :
public interface ISomeClass<T> where T : class
{
Int32 Count { get; }
}
public class SomeClass<T> : ISomeClass<T> where T : class
{
private readonly IEnumerable<ITestInterface<T>> _testInterfaces;
public SomeClass(IEnumerable<ITestInterface<T>> testInterfaces)
{
_testInterfaces = testInterfaces;
}
public Int32 Count
{
get
{
return this._testInterfaces.Count();
}
}
}
public interface ITestInterface {}
public interface ITestInterface<T> : ITestInterface { }
public class A { }
public class B { }
public class TestImplementationA : ITestInterface<A> { }
public class TestImplementationB : ITestInterface<B> { }
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<TestImplementationA>()
.As<ITestInterface<A>>()
.As<ITestInterface>();
builder.RegisterType<TestImplementationB>()
.As<ITestInterface<B>>()
.As<ITestInterface>();
builder.RegisterGeneric(typeof(SomeClass<>))
.As(typeof(ISomeClass<>));
IContainer container = builder.Build();
var x = container.Resolve<ISomeClass<A>>();
Console.WriteLine(x.Count);
var z = container.Resolve<IEnumerable<ITestInterface>>();
}
}
Code to demonstrate the problem:
static void Main(string[] args)
{
var a = new A();
var b = new B();
Base<>[] all = new Base<>[] { a, b }; // doesn't work
}
class Base<T>
{
public string Caption { get { return typeof(T).ToString(); } }
}
class A : Base<A> { }
class B : Base<B> { }
Perhaps I went the wrong direction. Idea was to move Caption into base class (Base become generic). Non-generic version works without problems:
var all = new Base[] { a, b }; // no problems for as long as Base is not generic
There's no Type<?> in C# - you always have to specify a concrete generic type.
The only way around this is to make Base<T> inherit a non-generic base-class, or implement a non-generic interface. You could then use that as the type of the array.
EDIT:
In your case this is extremely simple, since the part of the interface you want doesn't include the generic type argument. So you can simply do either:
public abstract class Superbase
{
public abstract string Caption { get; }
}
public class Base<T>: Superbase
{
public override string Caption { get { return typeof(T).Name; } }
}
Or, using an interface:
public interface IBase
{
string Caption { get; }
}
public class Base<T>: IBase
{
public string Caption { get { return typeof(T).Name; } }
}
Your array would then be Superbase[] or IBase[], respectivelly. In both cases, you can see that I'm not actually providing an implementation - both the declarations are "abstract", in a sense.
In general, I'm trying to keep the non-generic stuff in a non-generic base class, rather than stuffing it in the derived generic classes. It just feels more clean :)
based on #Luaan ideea, here is an implementation:
class Program
{
static void Main(string[] args)
{
var a = new A();
var b = new B();
var arr = new Base[] { a, b};
foreach (var obj in arr)
Console.WriteLine(obj.Caption);
Console.ReadKey();
}
}
public class Base<T> : Base
{
public override string Caption
{
get { return typeof (T).ToString(); }
}
}
public class A : Base<A> { }
public class B : Base<B> { }
public abstract class Base
{
public abstract string Caption { get; }
}
Instead of trying to use inheritance (which will lead to more problems down the line), use an extension method instead:
public interface IClassAORClassB {}
class A : IClassAORClassB { }
class B : IClassAORClassB { }
public static class Captions
{
public static string Caption<T>(this T obj) where T : IClassAORClassB
{
return obj.GetType().ToString();
}
}
static void Main(string[] args)
{
var a = new A();
var b = new B();
var all = new IClassAORClassB[] { a, b }; // works just fine
Console.WriteLine(all[0].Caption()); // prints A
Console.WriteLine(all[1].Caption()); // prints B
}
I would like to just use RegistrationBuilder to create parts.
example:
public interface IModel
{
String Name { get; }
}
public interface IRepository
{
}
class ModelOne : IModel
{
public String Name { get { return "ModelOne"; } }
}
class ModelTwo : IModel
{
public String Name { get { return "ModelTwo"; } }
}
public interface IRepository<TModel> : IRepository where TModel : IModel
{
}
public class Repository<TModel> : IRepository<TModel> where TModel : IModel
{
}
static void Main(String[] args)
{
var builder = new RegistrationBuilder();
builder.ForTypesDerivedFrom<IModel>()
.Export()
.Export<IModel>();
builder.ForTypesDerivedFrom<IRepository>()
.ExportInterfaces();
var asmCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly(), builder);
var container = new CompositionContainer(asmCatalog);
var one = container.GetExportedValue<IRepository<ModelOne>>();
var two = container.GetExportedValue<IRepository<ModelTwo>>();
}
I can not get the results(the one,the two) I want.
because when i use RegistrationBuilder the all type when wrapped in ProjectingType,but GetExportedValue method did not wrap Generic Parameters in ProjectingType.
My temporary solution is to delete the IsAssignableFrom method in ProjectingType. Now I can get the results(the one,the two) I want.
is there any good solution or correction?
I have three classes that will each return a slightly different result.
// interfact to a king
public interface IKing{
public Result Get();
}
// main abstract class
public abstract class King:IKing{
public abstract Result Get();
}
// main abstract result
public abstract class Result{
public int Type {get;set;}
}
// KingA result
public class ResultA:Result{
...
}
// KingB result
public class ResultB:Result{
...
}
// concrete implementations
public class KingA:King{
public override ResultA Get(){
return new ResultA;
}
}
public class KingB:King{
public override ResultB Get(){
return new ResultB
}
}
This will not work since the King overriden method of Get is expecting the Result class and will not accept its children ResultA and ResultB.
Is there a better approach I can take?
The usual approach is to use generics.
public interface IKing<T> where T:Result{
T Get();
}
public class King<T> : IKing<T>
public abstract T Get();
}
public class KingA : King<ResultB> {
public override ResultA Get(){
return new ResultA();
}
}
public class KingB : King<ResultB> {
public override ResultB Get(){
return new ResultB();
}
}
Edit: fixed syntax.
It will help if you use code that compiles. Your 'concrete implementations' are bogus, it looks like you mixed the concepts of class and method. There is otherwise no design problem here. For example:
public class KingA : King {
public override Result Get() {
return new ResultA();
}
}
I think there's some syntax confusion here -- if I captured your intent correctly, this works fine:
// interface to a king
public interface IKing
{
Result Get();
}
// main abstract class
public abstract class King : IKing
{
public abstract Result Get();
}
// main abstract result
public abstract class Result
{
private int _Type;
public int Type { get { return _Type; } set { _Type = value; } }
}
// KingA result
public class ResultA : Result
{
}
// KingB result
public class ResultB : Result
{
}
// concrete implementations
public class KingA : King
{
public override Result Get()
{
return new ResultA();
}
}
public class KingB : King
{
public override Result Get()
{
return new ResultB();
}
}
class Program
{
static void Main(string[] args)
{
IKing ka = new KingA();
IKing kb = new KingB();
Result ra = ka.Get();
Result rb = kb.Get();
if (ra is ResultA)
{
Console.WriteLine("A ok!");
}
if (rb is ResultB)
{
Console.WriteLine("B ok!");
}
}
}
(edited for formatting)
You should be able to explicitly cast ResultA and ResultB as Result in the implementations of Get (I'm assuming that's what the "concrete implementations" are intended to be).