I'm using C# under VS2012 v.11.0.61030.00 Update 4. I have a class with two constructors: one for normal use, and one that injects a dependency for the purposes of unit testing.
using ServiceLayer;
namespace PresentationLayer
{
public class Orchestrator
{
private NumberService svc;
public Orchestrator(int i)
{
svc = new NumberService(i);
}
public Orchestrator(NumberService providedService)
{
svc = providedService;
}
public int Get()
{
return svc.GetInt();
}
}
}
The "NumberService" is in a second project:
namespace ServiceLayer
{
public class NumberService
{
private int x;
public NumberService(int i)
{
x = i;
}
public int GetInt()
{
return x;
}
}
}
The PresentationLayer project is in turn referenced by the app (in this case, a console app):
using System;
using PresentationLayer;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Orchestrator o = new Orchestrator(8);
Console.WriteLine(o.Get());
}
}
}
The line Orchestrator o = new Orchestrator(8);
throws a compiler error as follows:
The type 'ServiceLayer.NumberService' is defined in an assembly that is not referenced. You must add a reference to assembly 'ServiceLayer, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
This appears to be because VS cannot differentiate between the two constructors without knowing what a NumberService is. However, if I change the number of parameters...
public Orchestrator(int i, bool b)
{
svc = new NumberService(i);
}
and
static void Main(string[] args)
{
Orchestrator o = new Orchestrator(8, true);
Console.WriteLine(o.Get());
}
Suddenly it's quite happy to compile. I feel that one of these two behaviors is in error: either it's okay not to know what a given class is, or it's not. Does anyone have a better explanation or fix for this?
It's okay not to understand a particular class when you know that its use is in a member that's definitely not applicable for the call you're making, because you're specifying two arguments and the member only takes one parameter.
It's not okay to not know whether the call is even valid, because you don't know (for example) whether there's an implicit conversion from int
to NumberService
. In this particular case this couldn't change overload resolution (I think...) but in other cases it might. Imagine if your int
parameter was actually object
, for example...
Personally I would be very wary of using a class where some of its public API depends on types in an assembly you don't have a reference to. You're operating somewhat in the dark. I suggest you just add an appropriate reference, or make the constructor internal to remove it from the public API. There's no point in having a public API that you don't actually want other code to be able to understand. If this is just for the sake of unit testing, then make the constructor internal
and use InternalsVisibleTo
to expose it (and other internal members) to your unit test assembly.
See more on this question at Stackoverflow