I am having trouble using Ninject to load my generic type implementations given the following simplified interface/class structure.
public interface IEntry {}
public class TestEntry : IEntry {}
public interface IDBConnection<T> {}
public class DBConnection<T> : IDBConnection<T> where T : IEntry {}
I am using binds within my loaded NinjectModule:
Bind<IEntry>().To<TestEntry>();
Bind(typeof(IDBConnection<>)).To(typeof(DBConnection<>));
I want to fetch an instance of DBConnection<TestEntry> with a call of:
Kernel.TryGet<IDBConnection<IEntry>>();
However this just returns an open instance type of DBConnection<IEntry> ; I have been able to return an instance of DBConnection<TestEntry> if I change my Kernel.Get call to:
Kernel.TryGet<IDBConnection<TestEntry>>();
I understand that generics are incovariant but it seems that we circumvent the entire purpose of DI/IOC if I need to stipulate the implementation of my generic class in order for Ninject to load it... So I must be either binding, fetching or understanding things incorrectly.
Furthermore I tried a different approach to binding/loading:
Bind<IEntry>().To<TestEntry>();
Bind(typeof(IDBConnection<IEntry>)).To(typeof(DBConnection<TestEntry>));
and
Kernel.TryGet<IDBConnection<IEntry>>();
However, this yields the exception:
System.InvalidCastException : Unable to cast object of type
'DBConnection1[TestEntry]' to type 'IDBConnection1[IEntry]'.
This is because the generic type IDBConnection<IEntry> is not covariant with DBConnection<TestEntry> right?
I want to be able to Ninject DBConnection<TestEntry> into my IDBConnection<IEntry> declaration for consumption; however incovariance of generics seems to disallow this. What's the solution?
Edit: Here is a unit Test to demonstrate/explain
public interface IEntry { }
public class TestEntry : IEntry { }
public interface IDBConnection<T> where T : IEntry { }
public class DBConnection<T> : IDBConnection<T> where T : IEntry { }
class TestModule : NinjectModule
{
public override void Load()
{
Bind<IEntry>().To<TestEntry>();
Bind(typeof(IDBConnection<IEntry>)).To(typeof(DBConnection<TestEntry>));
}
}
[Test]
public void NinjectGenericLoadTest()
{
/// this loads the expected type from interfaces however is useless
/// since loaded against a "var"
///(runtime casts knowing the impl would be required to use)
StandardKernel kernel = new StandardKernel(new TestModule());
var ninjected = kernel.TryGet(typeof(IDBConnection<IEntry>));
Assert.IsInstanceOf<DBConnection<TestEntry>>(ninjected);
/// The following is what I want but it won't compile
///:"Cannot implicitly convert type 'object' to
///'EasyMongo.Contract.IReader<EasyMongo.Contract.IEasyMongoEntry>'.
/// An explicit conversion exists (are you missing a cast?)"
//kernel = new StandardKernel(new TestModule());
//IDBConnection<IEntry> ninjectedInterface = kernel.TryGet(typeof(IDBConnection<IEntry>));
//Assert.IsInstanceOf<DBConnection<Entry>>(ninjectedInterface);
/// this throws System.InvalidCastException : Unable to cast object of type
/// 'DBConnection`1[EasyMongo.Test.Base.RandomTest+Entry]'
/// to type 'IDBConnection`1[EasyMongo.Test.Base.RandomTest+IEntry]'.
/// this is due to incovariance of generic types such that DBConnection<Entry>
/// is not a IDBConnection<IEntry>
IDBConnection<IEntry> ninjectedInterface = (IDBConnection<IEntry>)kernel.TryGet(typeof(IDBConnection<IEntry>));
Assert.IsInstanceOf<DBConnection<TestEntry>>(ninjectedInterface);
}
Ninject will always return the type you ask for. If you ask for IDBConnection<IEntry> then you will get that type if you ask for IDBConnection<TestEntry>. There is no super logic that will analyze your code and get you a different type then the one you are asking for.
But asking for things like IDBConnection directly is the wrong way to use Ninject anyway. You should inject it using constructor injection:
public class NeedDbConnection<T> {
public NeedDbConnection(IDBConnection<T> connection) { ... }
}
That way you get your specific db connection appropriate for that class.
Related
I'm trying to create an abstract proxy for several interfaces. Obviously both a concrete proxy implementation and the concrete proxied class it 'fronts' must implement the same interface. The proxy accepts the proxied class (to proxy to). Ideally I wouldn't constrain the interfaces at all but I don't believe C# allows constraining a generic type to being an interface. As such, my sample below uses IProxiableInterface to enforce.
Here's some sample code that all appears fine except for this problem:
Without the parent class, Rider complains "'T': type name expected"
With the parent class, Rider says "'T': interface name expected".
For both, the compiler says "error CS0689: Cannot derive from 'T' because it is a type parameter"
Both of them allow the concrete proxy to fail to implement the interface.
abstract class AbstractProxy<T> : /*MonoBehaviour,*/ T // <-- Error: "'T': type name expected" or "'T': interface name expected"
where T : IProxiableInterface
{
protected T impl;
public AbstractProxy(T impl) {
this.impl = impl;
}
}
interface IProxiableInterface {}
interface IFriendly : IProxiableInterface {
string sayHi();
}
sealed class HiSayer : IFriendly {
public string sayHi() => "Hi";
}
sealed class HiProxy : AbstractProxy<IFriendly> {
public HiProxy(IFriendly impl) : base(impl) {}
public string sayHi() => impl.sayHi(); // <-- _should_ be an error when omitted but not because the interface constraint is ignored
}
sealed class User {
public User() {
IFriendly friendlyToBeProxied = new HiSayer();
IFriendly friendlyProxy = new HiProxy(friendlyToBeProxied);
Console.WriteLine(friendlyProxy.sayHi());
}
}
So it seems C# disallows this approach (which I learnt after typing all of this into StackOverflow and getting hinted with this question :) ).
For now I've had to remove the constraint on AbstractProxy so it doesn't have to implement the interface. As a workaround I've added an assertion to a factory method that takes an extra generic type indicating the type being built:
Assert.IsTrue(typeof(T1).IsAssignableFrom(typeof(T2)), "T2 \"{1}\" must implement T1 \"{2}\" for {0}", go, typeof(T2), typeof(T1));
So what's a better solution The Right Way to solve this, please?
This is the kind of scenario that requires meta-programming; specifically, you need to implement a specific interface only known at runtime, which isn't something you can express against a pre-compiled type. Typically, you would end up using TypeBuilder to create a new type at runtime, implementing the type you need, and then using reflection to inspect the interface you want looking for the members you need, adding those onto your new type (MethodBuilder etc), and writing an implementation (ILGenerator) that invokes whatever proxy logic you need (which may involve writing a constructor via ILGenerator that takes the proxy instance as a parameter and stores it in a field, then access the field in each method for the proxy step). You'd then create the concrete type, and store that somewhere as a cache (because all this TypeBuilder work is expensive). This is a lot of work! As a starting point: here's the proxy emitter for protobuf-net.Grpc
Looks like you want your AbstractProxy to use composition rather than inheritance, so you don't need it to derive from anything:
abstract class AbstractProxy<T> where T : IProxiableInterface
{
protected T impl;
public AbstractProxy(T impl)
{
this.impl = impl;
}
}
IProxiableInterface defines no behaviour so it seems that you are using it simply to constrain the generic types.
This would then be fine:
sealed class HiProxy : AbstractProxy<IFriendly>
{
public HiProxy(IFriendly impl) : base(impl) {}
public string sayHi() => impl.sayHi();
}
We have an interface to deal with DAL with pretty simple definition:
interface IRepository<T> : IQueriable<T> // so we can read data from database
{
Save(T document); // dozen of methods here
}
Mostly we use two implementations: real version and in memory version for unit testing. Here is declarations of one of class:
public RealRepository : IRepository<AccountEntity> { ... }
// typical IOC usage
services.AddSingleton<IRepository<AccountEntity>, RealRepository<AccountEntity>>();
Now we are working to spin off for main codebase to custom version of project and we need custom fields in data and occassional custom behavior in repository. Most of classes are fine with base implementation but others would require specific implementation. So my goal is to get to following services in:
var repository = new RealRepository<CustomAccountEntity>();
services.AddSingleton(IRepository<AccountEntity>, repository);
// for new classes
services.AddSingleton(IRepository<CustomAccountEntity>, repository);
I tried to add out T to IRepository but I am using T in input parameters and this gave compile time "Invalid variance" error.
I can see a solution by adding second type parameter to interface so it looks like:
IRepository<TBase, out TChild> : IQueriable<TChild> {
Save (T document);
}
Finally, Question: How can make change 100% backward compatible?
What I tried:
Add IRepository<T>: IRepository<T,T> -> complies, but RealRepository is not implementing IRepository anymore.
Add 2 interfaces in implementation: public class RealRepository<TBase, TChild>: IRepository<TBase, TChild>, IRepository<TChild> but this gives compliation error 'cannot implement both ... and ... because they may unify for some type parameter substitutions'
Save(T document) has T in a contravariant position. That means in T, not out T.
Let's recap what contravariance means. Suppose you had this code:
using System;
public class Entity {}
public class AccountEntity : Entity {}
public class CustomAccountEntity : AccountEntity {}
public interface IQueryable<in T>
where T : Entity
{}
public interface IRepository<in T>
where T : Entity
{
void Save(T record);
}
public class EntityRepository<T> : IRepository<T>
where T : Entity
{
public void Save(T record) {}
}
public class Program
{
public static void Main()
{
// This is ***VALID***:
IRepository<CustomAccountEntity> repo = new EntityRepository<AccountEntity>();
Console.WriteLine(repo == null ? "cast is invalid" : "cast is valid");
}
}
https://dotnetfiddle.net/cnEdcm
So whenever you need a IRepository<CustomAccountEntity>, you can use a concrete EntityRepository<AccountEntity> instance. Seems counter-intuitive, but it's actually totally right: If the concrete method is Save(AccountEntity), it can obviously handle CustomAccountEntity instances too; OTOH if the concrete method were Save(CustomAccountEntity), it would NOT be able to handle simple AccountEntity instances.
Having said that, then I think you should
Use contravariance instead;
Declare all dependencies using the most specialised type, e.g. IRepository<CustomWhateverEntity>;
In the IoC registration code, for each particular entity, setup either Repository<CustomeWhateverEntity>, if you need the extra behaviour, or just Repository<WhateverEntity> otherwise.
I'm trying to create a simple object recycling class
public class ObjectPool<T> where T : class, IRecyclable, new()
{
}
I want to be able to use it with my interface:
public interface ISomeInterface : IRecyclable
{
}
ObjectPool<ISomeInterface> pool = new ObjectPool<ISomeInterface>();
But this yields the error:
error CS0310: The type `ISomeInterface' must have a public parameterless constructor in order to use it as parameter `T' in the generic type or method `ObjectPool<T>'
From what I have read online I know that I can't specify a constructor in an interface.
I have read that you can use reflection instead of "new" to create a new instance, though I'm concerned about the speed of performing this instantiation.
What is the correct way to resolve this situation? Is there a simpler solution that I'm completely overlooking?
Interfaces can only implement other interfaces.
interface IA : IB, IC
{
...
}
A good way to solve your dilemma is to introduce a factory interface as well.
interface IThing
{
...
}
interface IThingFactory
{
IThing Create();
}
Now anything that wants to have the ability to create things should receive an IThingFactory for that purpose.
If you need a generic concept of a factory, you could use something like this:
interface IFactory<T>
{
T Create();
}
class ObjectPool<T, F>
where T : IRecyclable
where F : IFactory<T>
{
public ObjectPool(F factory)
{
...
}
}
You can't provide an interface there. class and new require it to be a constructable reference type.
You cannot construct an ObjectPool<ISomeInterface>. You could have a generic type MyClass<TT> where T:class,ISomeInterface,new() declare an ObjectPool<TT> within it, and then later on declare variables of type MyClass<SomeClassWhichImplementsISomeInterfaceAndHasADefaultConstructor>, but the compiler can only execute methods for ObjectPool<T> when T is of a particular known class type which meets all the constraints.
Alternatively, you could omit the new constraint and then require that any code which constructs an ObjectPool<T> must pass the constructor (or other method that creates the instance) a Func<T>. That would make it possible to create an ObjectPool<ISomeInterface> provided that one had a method which, when called, would return a new object of some suitable type that implemented ISomeInterface.
I do have a class, which is defined as:
public abstract class Singleton <T> : BaseObject
where T : Singleton <T>
{
}
I want to define an array of those generic singletons somewhere else. Something like
public MonoSingleton[] singletons;
How can I retrieve the proper type of that generic (that seems to be recursive, as you may see)? How can I write this out?
Are you trying to do the 'curiously recursive template pattern', like this?
class CuriouslyRecursiveBase<T>
{
}
class CuriouslyRecursiveDervied<T> : CuriouslyRecursiveBase<T>
{
}
class MyClass : CuriouslyRecursiveBase<MyClass>
{
}
To instantiate the derived from the base, you just use:
class CuriouslyRecursiveBase<T>
{
public static void InstantiateDerived()
{
T instance = (T)Activator.CreateInstance(typeof(T));
}
}
Since T is actually the derived type (MyClass) and curiously is also type (CuriouslyRecursive<MyClass>).
Specifically applied to your problem:
// Create a common interface that all singletons use. This allows
// us to add them all to a list.
interface ISingleton { }
class Singleton<T> : ISingleton
{
// Store our list of ISingletons
static List<ISingleton> instances = new List<ISingleton>();
static T instance;
protected Singleton() { }
public static T GetInstance()
{
// Either return the existing instnace, or create a new one
if (Singleton<T>.instance == null)
{
Singleton<T>.instance = (T)Activator.CreateInstance(typeof(T));
// Use a common interface so they can all be stored together.
// Avoids the previously mentioned co-variance problem.
// Also, compiler isn't built to follow curious recursiveness,
// so use a dynamic statement to force runtime re-evaluation of
// the type hierarchy. Try to avoid dynamic statements in general
// but in this case its useful.
instances.Add((dynamic)Singleton<T>.instance);
}
return Singleton<T>.instance;
}
}
class MyClass : Singleton<MyClass>
{
}
public static void Main()
{
MyClass my = MyClass.GetInstance();
}
More info:
http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Using design-time code, you'll be able to get the type by using the typeof operator and giving some argument to the generic parameter:
typeof(Singleton<SomeImplementationOfBaseObject>)
Or
typeof(Singleton<>)
But there's an alternative: reflection.
Type singletonType = Type.GetType("NamespaceA.NamespaceN.Singleton`1");
The 1 part is the number of generic parameters. If you've something like Class<T, S> it would be 2 and so on.
Note that using reflection you don't need to give the generic argument. You can get the type with the generic parameter anyway. In order to give the generic argument, you would do this:
Type genericType = singletonType.MakeGenericType(typeof(SomeImplementationOfBaseObject));
Or if you want to get it directly, you would do this:
Type singletonType = Type.GetType("NamespaceA.NamespaceN.Singleton`1[[NamespaceA.NamespaceN.SomeImplementationOfBaseObject]]");
The string inside [[ ]] its the full name for the type passed as generic argument. Note that if the generic type isn't the same assembly as the executing one, you'll need to provide an assembly qualified name (for example, "NamespaceA.MyClass, MyAssembly").
UPDATE
The OP said in some comment:
If I do use: public Singleton<BaseObject>[] singletons;, it warns me
with: 'error CS0309: The type BaseObject' must be convertible to
Singleton' in order to use it as parameter 'T' in the
generic type or method 'Singleton'
This is another problem: you can't do covariance in classes. For doing such thing, you'll need an interface like this:
public interface ISingleton<out TBaseObject> where TBaseObject : .........
And make the Singleton<T> class implement it.
Thus, you can create such array this way:
public ISingleton<BaseObject>[] singletons;
Covariance lets you upcast generic parameters and it's limited to interfaces and delegates.
Learn more here:
http://msdn.microsoft.com/en-us/library/ee207183.aspx
I need to have the generic type parameter as an interface, however I would like to instantiate the type in the generic class (SomeGenericType) as follows:
class Program
{
static void Main(string[] args)
{
var val = new SomeGenericType<ISomeInterface>();
Console.ReadKey();
}
}
internal class SomeGenericType<T> where T : new()
{
public SomeGenericType()
{
var test = new T();
}
}
public class SomeClass : ISomeInterface
{
public string TestVal { get; set; }
}
public interface ISomeInterface
{
string TestVal { get; set; }
}
This throws the following compile time error:
"ISomeInterface must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method SomeGenericType"
I understand why it happens, however I was wondering if there is any way around this problem?
Thanks.
No, the new() constraint requires that an instance of the type can be created with the syntax
new T()
This clearly isn't true of either an abstract class or an interface, only a concrete class with a public parameterless constructor.
You could defer the problem until runtime by removing the constraint, and using:
Activator.CreateInstance<T>()
instead to create the object. Then as long as the actual type used at runtime satisfies these constraints, your code will work as you want it to. However, if you do attempt to use an interface or an abstract class, then you will encounter a runtime error.
In your specific case, this line would throw an exception
var val = Activator.CreateInstance<SomeGenericType<ISomeInterface>>();
You're past the compile-time error, but to no effect.
An alternative idea, which may be irrelevant, but it looks like you are looking for a way to ask for an ISomeInterface, and have an instance of its "default" implementation SomeClass provided. This is the sort of thing that an Inversion of Control (IOC) container can handle for you. If you want to investigate further, you could look at Spring.NET, Microsoft Unity, AutoFac, LinFu or one of many other frameworks.
The problem is, there is no way for the compiler to know which class to instantiate for the given interface. As David M points out:
This is the sort of thing that an Inversion of Control (IOC) container can handle for you
I think using a framework might be over kill for this simple requirement. What you can do is create a Factory class of your own like this:
public class Factory
{
Dictionary<Type, Type> typeMapping = new Dictionary<Type, Type>();
public void Register<IType, CType>()
{
typeMapping.Add(typeof(IType),typeof(CType));
}
public IType Create<IType>()
{
Activator.CreateInstance(typeMapping[typeof(IType)]);
}
}
throw in a few sanity checks and this class should be ready to use.
The issue here is the new constraint is tied to having a concrete type implementation. This can't ever work with simply and interface or abstract class since they cannot be directly instantiated. You must provide a concrete class here
var val = new SomeGenericType<SomeClass>()