I've got the following interfaces:
public interface IObjectFinder<T> where T : IObject
{
Task<IObjectResults<T>> FindAsync(string name);
}
public interface IObject
{
string Id { get; }
}
I'd like to initialize a dictionary with the following:
this.finders = new Dictionary<string, IObjectFinder<IObject>>();
finders.Add("Car", new CarFinder<Car>());
finders.Add("Truck", new TruckFinder<Truck>());
Then create a simple controller method:
public async Task<IActionResult>(string objectType, string searchTerm)
{
if (!finders.TryGetValue(objectType, out var finder))
return NotFound();
var result = await finder.FindAsync(searchTerm);
return Ok(result);
}
The problem is the IObjectFinder<IObject> type of dictionary. A CarFinder<Car> isn't an IObjectFinder<IObject>. Is there an objectively better way to handle this? I'd like to avoid using MorseCode.ITask and dynamic's to avoid muddying up the code even more. How would you handle something like this?
After I thought some more, I think it's similar to how some generic interfaces (e.g. IEnumerator<T> and IEnumerator) are defined. We need to define some non-generic interfaces first:
public interface IObjectResults
{
}
public interface IObjectFinder
{
Task<IObjectResults> FindAsync(string name);
}
The generic interfaces need inherit them, and benefit from the default interface methods feature, we can implement them in this place.
public interface IObjectResults<T> : IObjectResults where T : IObject
{
}
public interface IObjectFinder<T> : IObjectFinder where T : IObject
{
new Task<IObjectResults<T>> FindAsync(string name);
async Task<IObjectResults> IObjectFinder.FindAsync(string name)
=> await FindAsync(name);
}
Now it's able to replace IObjectFinder<IObject> with IObjectFinder in the dictionary.
this.finders = new Dictionary<string, IObjectFinder>();
finders.Add("Car", new CarFinder());
var result = await finder.FindAsync(searchTerm);
Related
To be honest I wasn't sure how to word this question so forgive me if the actual question isn't what you were expecting based on the title. C# is the first statically typed language I've ever programmed in and that aspect of it has been an absolute headache for me so far. I'm fairly sure I just don't have a good handle on the core ideas surrounding how to design a system in a statically typed manner.
Here's a rough idea of what I'm trying to do. Suppose I have a hierarchy of classes like so:
abstract class DataMold<T>
{
public abstract T Result { get; }
}
class TextMold : DataMold<string>
{
public string Result => "ABC";
}
class NumberMold : DataMold<int>
{
public int Result => 123
}
Now suppose I want to make a list of item where the items can be any kind of mold and I can get the Result property of each item in a foreach loop like so:
List<DataMold<T>> molds = new List<DataMold<T>>();
molds.Add(new TextMold());
molds.Add(new NumberMold());
foreach (DataMold<T> mold in molds)
Console.WriteLine(mold.Result);
As you probably already know, that doesn't work. From what I've read in my searches, it has to do with the fact that I can't declare the List to be of type DataMold<T>. What is the correct way to go about something like this?
The short answer: You can't.
One of the things that is counterintuitive about generic types is that they are not related. A List<int>, for example, has no relationship whatsoever to a List<string>. They do not inherit from each other, and you can't cast one to the other.
You can declare a covariance relationship, which looks a lot like an inheritance relationship, but not between an int and a string as you have declared, since one is a value type and one is a reference type.
Your only alternative is to add another interface that they have in common, like this:
interface IDataMold
{
}
abstract class DataMold<T> : IDataMold
{
public abstract T Result { get; }
}
Now you can store all of your molds in a List<IDataMold>. However, the interface has no properties, so you'd have a heckuva time getting anything out of it. You could add some properties, but they would not be type-specific, as IDataMold has no generic type parameter. But you could add a common property
interface IDataMold
{
string ResultString { get; }
}
...and implement it:
abstract class DataMold<T>
{
public abstract T Result { get; }
public string ResultString => Result.ToString();
}
But if your only need is to display a string equivalent for each item, you can just override ToString() instead:
class TextMold : DataMold<string>
{
public string Result => "ABC";
public override string ToString() => Result.ToString();
}
Now you can do this:
List<IDataMold> molds = new List<IDataMold>();
molds.Add(new TextMold());
molds.Add(new NumberMold());
foreach (var mold in molds)
{
Console.WriteLine(mold.ToString());
}
You're looking for covariance. See the out keyword before T generic type parameter:
// Covariance and contravariance are only possible for
// interface and delegate generic params
public interface IDataMold<out T>
{
T Result { get; }
}
abstract class DataMold<T> : IDataMold<T>
{
public abstract T Result { get; }
}
class StringMold : DataMold<string> {}
class Whatever {}
class WhateverMold : DataMold<Whatever> {}
Now inherit DataMold<T> and create a List<IDataMold<object>>:
var molds = new List<IDataMold<object>>();
molds.Add(new StringMold());
molds.Add(new WhateverMold());
BTW, you can't use covariance when it comes to cast IDataMold<int> to IDataMold<object>. Instead of repeating what's been already explained, please see this other Q&A: Why covariance and contravariance do not support value type
If you're really forced to implement IDataMold<int>, that list may be of type object:
var molds = new List<object>();
molds.add(new TextMold());
molds.add(new NumberMold());
And you may use Enumerable.OfType<T> to get subsets of molds:
var numberMolds = molds.OfType<IDataMold<int>>();
var textMolds = molds.OfType<IDataMold<string>>();
Also, you may create two lists:
var numberMolds = new List<IDataMold<int>>();
var textMolds = new List<IDataMold<string>>();
So you might mix them later as an IEnumerable<object> if you need to:
var allMolds = numberMolds.Cast<object>().Union(textMolds.Cast<object>());
You could use a visitor pattern:
Add a visitor interface that accepts all your types, and implement a visitor that performs the action you want to apply to all DataMolds:
interface IDataMoldVisitor
{ void visit(DataMold<string> dataMold);
void visit(DataMold<int> dataMold);
}
// Console.WriteLine for all
class DataMoldConsoleWriter : IDataMoldVisitor
{ public void visit(DataMold<string> dataMold)
{ Console.WriteLine(dataMold.Result);
}
public void visit(DataMold<int> dataMold)
{ Console.WriteLine(dataMold.Result);
}
}
Add an acceptor interface that your list can hold and have your DataMold classes implement it:
interface IDataMoldAcceptor
{ void accept(IDataMoldVisitor visitor);
}
abstract class DataMold<T> : IDataMoldAcceptor
{ public abstract T Result { get; }
public abstract void accept(IDataMoldVisitor visitor);
}
class TextMold : DataMold<string>
{ public string Result => "ABC";
public override void accept(IDataMoldVisitor visitor)
{ visitor.visit(this);
}
}
class NumberMold : DataMold<int>
{ public int Result => 123;
public override void accept(IDataMoldVisitor visitor)
{ visitor.visit(this);
}
}
And finally, execute it with:
// List now holds acceptors
List<IDataMoldAcceptor> molds = new List<IDataMoldAcceptor>();
molds.Add(new TextMold());
molds.Add(new NumberMold());
// Construct the action you want to perform
DataMoldConsoleWriter consoleWriter = new DataMoldConsoleWriter();
// ..and execute for each mold
foreach (IDataMoldAcceptor mold in molds)
mold.accept(consoleWriter);
Output is:
ABC
123
dynamic
This can be done with the dynamic keyword, at the cost of performance and type safety.
var molds = new List<object>(); // System.Object is the most derived common base type.
molds.Add(new TextMold());
molds.Add(new NumberMold());
foreach (dynamic mold in molds)
Console.WriteLine(mold.Result);
Now that mold is dynamic, C#'ll check what mold's type is at run-time and then figure out what .Result means from there.
I have a class which works with a hardware device. This device supports a number of commands, and I want to implement a common SendCommand function. Commands might or might not have input parameters and/or output result.
What I can do is to write an abstract command type class, and a number of derived command type classes. Those derived classes would actually be different with those input/output specifics of commands.
Now I want SendCommand to return a Task<SpecificCommandType>, that is, task of derived class, but with current design I can only return Task<BaseCommandType>.
I will explain with simple skeleton code:
Classes:
public abstract class BaseCommandType { ... }
public class CommandType1 : BaseCommandType {
TaskCompletionSource<CommandType1> Tcs;
}
public class CommandType2 : BaseCommandType {
TaskCompletionSource<CommandType2> Tcs;
}
My function:
public Task<T> SendCommand<T>(BaseCommandType type) where T : BaseCommandType {
...
// if I implement TaskCompletionSource<BaseCommandType> Tcs
// in abstract class, then I can return type.Tcs.Task, and remove
// generics.
// But how can I return Task<T>?
}
I was planned to use this func like this:
CommandTypeX cmd = new CommandTypeX(...);
SendCommand<CommandTypeX>(cmd).ContinueWith(t => {
// access some specifics of t.Result as CommandTypeX
});
How should I design my classes to be able to return Task<CommandTypeX>?
Or is there a better way to do something I need (without downcast)?
Update1:
To be more precise, I can do it like this with downcast (can do I, isn't it?):
public abstract class BaseCommandType {
public TaskCompletionSource<BaseCommandType> Tcs;
}
public class CommandTypeX : BaseCommandType { }
public Task<BaseCommandType> SendCommand(BaseCommandType type) {
...
return type.Tcs.Task;
}
// when task finishes:
type.Tcs.SetResult(type); // where type is actually of CommandTypeX
// usage:
CommandTypeX cmd = new CommandTypeX(...);
SendCommand(cmd).ContinueWith(t => {
CommandTypeX command = t.Result as CommandTypeX;
if (command != null) ...
});
But that's exactly what I want to avoid in first place.
Update2:
I think I found another way of going, but still looks not well for me.
public abstract class BaseCommandType {
internal abstract void SetTcs<T>(TaskCompletionSource<T> tcs);
internal abstract void HandleData(byte[] data);
}
public class CommandType1 : BaseCommandType {
private TaskCompletionSource<CommandType1> _tcs1 = new TaskCompletionSource<CommandType1>();
public string Data1;
internal override void SetTcs<T>(TaskCompletionSource<T> tcs)
{
_tcs1 = tcs as TaskCompletionSource<CommandType1>;
}
internal override void HandleData(byte[] data)
{
// Data1 = someFuncOn(data)
_tcs1.TrySetResult(this);
}
}
public class CommandType2 : BaseCommandType {
private TaskCompletionSource<CommandType2> _tcs2 = new TaskCompletionSource<CommandType2>();
public int[] Data2;
internal override void SetTcs<T>(TaskCompletionSource<T> tcs)
{
_tcs2 = tcs as TaskCompletionSource<CommandType2>;
}
internal override void HandleData(byte[] data)
{
// Data2 = someFuncOn(data)
_tcs2.TrySetResult(this);
}
}
public class Device {
private List<BaseCommandType> _commandList = new List<BaseCommandType>();
public Task<T> SendCommand<T>(T t) where T : BaseCommandType
{
TaskCompletionSource<T> tcs = new TaskCompletionSource<T>();
t.SetTcs<T>(tcs);
_commandList.Add(t);
// later in other thread then device answers
// locate command in list
// BaseCommandType c = _commandList[some index];
// _commandList.RemoveAt(some index);
// c.HandleData(null);
return tcs.Task;
}
}
// usage like this:
CommandType2 command = new CommandType2();
device.SendCommand<CommandType2>(command).ContinueWith(t =>
{
CommandType2 command2 = t.Result;
// use command2.Data2 here;
});
Is this way better than in update1? At least I can hide the casting logic inside the library so externally everything would be type safe and robust.
Or how can I further improve on this?
I'm not sure whether I understood it right, but...
public abstract class BaseCommandType<T>
{
public abstract TaskCompletionSource<T> Tcs { get; }
}
public class CommandType1 : BaseCommandType<CommandType1>
{
}
public class CommandType2 : BaseCommandType<CommandType2>
{
}
public Task<T> SendCommand<T>(T type) where T : BaseCommandType<T>
{
return type.Tcs.Task;
}
EDIT:
If you cannot have generic input parameter, than instead of downcasting define abstract beahvior on BaseCommandType, which you would call in ContinueWith method, and override it in your commands. If you don't know the input type you cannot make it generic.
Things I don't understand about your question:
Why the restriction on the parameter type for SendCommand<T>(BaseCommandType)? What wouldn't work if you make that method SendCommand<T>(T) instead?
Why are you using ContinueWith()? await would be easier and more expressive.
Ignoring those for a moment, I would expect you should be able to do something like this:
public async Task<T> SendCommand<T>(BaseCommandType type) where T : BaseCommandType
{
return await type.Tcs.Task as T;
}
Personally, I would go all-generic. But you say you can't for whatever reason, so you're going to have to cast at some point. Avoiding casting simply isn't possible with that constraint. The above seems like the easiest, most usable approach to do that.
If the above does not address your need, please improve the question by including a good Minimal, Complete, and Verifiable code example that shows clearly all the design restrictions and requirements, what you've tried, and explain why what you've tried does not meet your goal.
This is part of my code which I need help with:
// simple service locator
public class ServiceManager<TSvc> : IServiceManager<TSvc> where TSvc: class, IService
{
private Dictionary<object, TSvc> services;
public void RegisterService(TSvc service)
{
// omitted code here
this.services.Add(service.GetType(), service); // dictionary
}
public T GetService<T>() where T : TSvc
{
T result = default(T);
TSvc bufResult = null;
if (this.services.TryGetValue(typeof(T), out bufResult))
result = (T)bufResult;
return result;
}
public TSvc GetService(Type serviceType)
{
TSvc result = null;
this.services.TryGetValue(serviceType, out result);
return result;
}
}
Then my domain interfaces:
public interface IItem
{
string Name { get; set; }
}
public interface IRepository<TModel> where TModel : IItem
{
new IEnumerable<TModel> GetItems();
void InsertItem(TModel item);
void UpdateItem(TModel item);
void DeleteItem(TModel item);
}
public interface IService<TModel> where TModel : IItem
{
IRepository<TModel> Repository { get; }
}
Then some of my domain classes:
public class Book: IItem
{
public string Name { get; set; }
}
public class BookRepo: IRepository<Book>
{
new IEnumerable<Book> GetItems();
void InsertItem(Book item);
void UpdateItem(Book item);
void DeleteItem(Book item);
}
public class BookService: IService<Book>
{
IRepository<Book> IService<Book>.Repository { get { return this.Repository; } }
BookRepo Repository { get; set;}
}
Now, if I am interested to use 'BookService' and do something with it, I could get it from service locator like this:
public void DoSomething()
{
var bookService = serviceManager.GetService<BookService>();
bookService.Repository.Insert(new Book());
}
But the problem is that the type of the service is known only at runtime (eg. selection from combobox). So, how would DoSomething method look like?
public void DoSomething()
{
var typeOfService = combobox.SelectedValue.GetType(); // cbx of services
// ??? make use of serviceManager and typeOfService to get appropriate 'service'
service.Repository.Insert(/*new IITem here*/);
}
Also, I would like to know how would you connect IService to IService<TModel>... it could even get to the solution, but I have no idea how. My IService interface is blank for the moment...
I would really appreciate your time. Please let me know if there is something unclear! Thank you!
Update: Based on your answers, I guess the reflection part could be involved (something like NSGaga pointed out), but still, without connecting IService and IService<TModel> I cannot achieve what I want. Who has any idea how to redesign this?
Something like this should work (typing from my head, so you'd need to check the syntax details - but should give you the direction - or I'll add on later)
MethodInfo methodInfo = typeof(ServiceManager).GetMethod("GetService");
MethodInfo methodInfoGeneric = methodInfo.MakeGenericMethod(new[] { typeOfService });
methodInfoGeneric.Invoke(serviceManager, new object[] { });
To call a generic method where the type is only known at runtime requires using reflection.
For example, in your last code sample, you rightly imply that you can't call GetService<BookService>, but you are still adding new Book() to the service. You would also have to use reflection to instantiate the new object, because, again, you don't know the type at compile time. So you would need to use reflection at least three times: Once to call the method that returns the service, once to create the new object, and once to call the insert method on the service.
You can isolate some of this complexity with dependency injection and inversion of control. For example, create a generic method like this:
void CreateNewObject<T>() where T : new()
{
var service = GetServiceFor<T>();
service.Repository.Insert(new T());
}
Now, you only need to use reflection once, to call that method, instead of three times.
I have a class Company that holds a list of different IFactory<IPart>; e.g. an EngineFactory.
public class Company
{
private Dictionary<Type, IFactory<IPart>> _factories;
public Company()
{
_factories = new Dictionary<Type, IFactory<IPart>>();
_factories[typeof (Engine)] = new EngineFactory();
}
public void SendOrderIntakeToFactory(IPart part)
{
}
}
The EngineFactory looks like this:
public class EngineFactory : IFactory<Engine>
{
public void Produce(Engine part)
{
}
}
And the IFactory interface:
public interface IFactory<T> where T : IPart
{
void Produce(T part);
}
This will result in a compiler error:
Cannot implicitly convert type 'EngineFactory' to 'IFactory'. An explicit conversion exists (are you missing a cast?)
on this line: _factories[typeof (Engine)] = new EngineFactory();
Ok that makes sense to me, without specifying the variance this will never work. So I tried to add the out keyword to the generic type T, but that will force me to remove the T as method parameter (because it's not allowed to use <out T> as input parameter):
public interface IFactory<out T> where T : IPart
{
void Produce(IPart part);
}
This clearly breaks my generic design. I am able to produce Wheels at my EngineFactory.
I understand the challenge lies in these two requirements:
Store the factory as IFactory<IPart>
The need for a generic void Produce(T part); implementation in the factories.
Is there any way of achieving this?
You can mark generic type parameter as covariant if it used only as return type of methods. Change Produce method to return part and all will work
public interface IFactory<out T> where T : IPart
{
T Produce();
}
You can't use covariant type parameter if it is used as method parameter.
BTW it's really strange factory which accepts objects instead of creating them.
UPDATE you can use runtime type definition with dynamic:
public class Company
{
private Dictionary<Type, dynamic> _factories;
public Company()
{
_factories = new Dictionary<Type, dynamic>();
_factories[typeof(Engine)] = new EngineFactory();
}
public void SendOrderIntakeToFactory(IPart part)
{
_factories[part.GetType()].Produce((dynamic)part);
}
}
When you will call
company.SendOrderIntakeToFactory(new Engine());
Then EngineFactory will be selected and it's Produce method will be called with parameter of runtime type Engine.
I think you could loosen up the dictionary a bit. Consider the following "factory container":
public class Factories
{
private Dictionary<Type, object> _factories;
public Factories()
{
_factories = new Dictionary<Type, object>();
_factories[typeof (Engine)] = new EngineFactory();
}
public IFactory<TPart> GetFactory<TPart>() where TPart:IPart
{
//TODO: add check whether typeof(TPart) exist in the dictionary
return (IFactory<TPart>)_factories[typeof(TPart)];
}
}
This implementation would allow you to do the following:
var factories = new Factories();
var engineFactory = factories.GetFactory<Engine>();
var engine = new Engine();
engineFactory.Produce(engine);
What you are specifically trying to do (mixing covariance and contra-variance) is a rabbit hole. The only solution is NOT to mix variance like this; Move to run-time type checking when you feel the need to mix variance.
[Updated] This would deal with both concerns (strongly typed and flexible location)
interface IPart{}
class Engine : IPart{}
interface IMachine
{
void Produce(IPart part);
Type Type { get; }
}
interface IGenericMachine<in TPart> : IMachine
{
void Produce(TPart with);
}
class EngineMachine : IGenericMachine<Engine>
{
public void Produce(Engine with)
{
}
public void Produce(IPart part)
{
if (part.GetType() != typeof(Engine))
throw new ArgumentException("part must be an Engine");
}
public Type Type { get { return typeof (Engine); } }
}
internal class MachineLocator
{
public Dictionary<Type, IMachine> Machines;
public IGenericMachine<TPart> GetMachine<TPart>()
{
return Machines
.Select(x => x.Value)
.OfType<IGenericMachine<TPart>>()
.Single();
}
public IMachine GetMachine(Type type)
{
return Machines
.Where(x => x.Value.Type == type)
.Select(x=>x.Value)
.Single();
}
}
class Program
{
static public void Main()
{
var locator = new MachineLocator();
locator.Machines.Add(typeof(EngineMachine), new EngineMachine());
var machineKnown = locator.GetMachine<Engine>();
var machineUnknown = locator.GetMachine(typeof(Engine));
machineUnknown.Produce(new Engine());
}
}
When all is said and done; have a look at Inversion of Control as a better design pattern for your program in general. Basically classes don't look for stuff, they get given it.
I have many classes that implements IBuilder<> interface such the ones below
UPDATED:
each Model1, Model2... inherits from IModel
public class A : IBuilder<Model1>
{
public Model1 Create(string param)
{
return new Model1();
}
}
public class B : IBuilder<Model2>
{
public Model2 Create(string param)
{
return new Model2();
}
}
I'm using StructureMap to register all classes that inherit IBuilder<>
Scan(x =>
{
x.TheCallingAssembly();
x.AddAllTypesOf(typeof(IViewModelBuilder<>));
});
UPDATED
Now, every time I need to get model of some Module I call Do function
public IModel Do(Module module)
{
//ModelSettings is taken from web.config
var builderType = Type.GetType(string.Format("{0}.{1}ModelBuilder,{2}", ModelSettings.Namespace, module.CodeName, ModelSettings.Assembly));
var builder = ObjectFactory.GetInstance(t) as IViewModelBuilder<>;
return builder.Create("");
}
I get compilation error in the line ObjectFactory.GetInstance(t) as IViewModelBuilder<>.
Many posts suggest to create NOT generic interface(IViewModelBuilder) and let the generic one to inherit it. And then I could make the casting like
ObjectFactory.GetInstance(t) as IViewModelBuilder
Is this the only way?
Thank you
Your code for Do and GetInstance should be generic too. Basicly it could look something like this
public T Do<T> ()
{
return ObjectFactory.GetInstance<T>().Create();
}
Couldn't you make Do() generic?
var m = Do<B>();
public T Do<T>()
{
var builder = (IViewModelBuilder<T>)ObjectFactory.GetInstance(typeof(T));
return builder.Create("");
}
If you can't, using non-generic interface is probably your best bet, but there are other options like using reflection or C# 4's dynamic:
var m = Do(typeof(B));
public object Do(Type t)
{
dynamic builder = ObjectFactory.GetInstance(t);
return builder.Create("");
}
The only thing I can think of is that you make an interface or a base class that your viewmodel inherit from. I.e:
public class Model1 : ModelBase
{
}
public class ModelBase
{
}
public ModelBase Do(Type t)
{
var builder = ObjectFactory.GetInstance(t);
return t.GetMethod("Create").Invoke(builder, new object[] { "" }) as ModelBase;
}
You need to introduce a non-generic IViewModelBuilder interface if you want to call it in a non-generic scenario. The generic IViewModelBuilder<T> would implement IViewModelBuilder.
The only other alternative is to invoke the create method via reflection, but I don't see why that would be preferred:
var builder = ObjectFactory.GetInstance(builderType);
var method = builderType.GetMethod("Create");
return (IModel) method.Invoke(builder, new[]{""});