imukai
imukai

Reputation: 688

C# Interface, Unity, and Optional Parameter

Hopefully someone can shed some light on this one. I have an interface with an optional parameter. We use Unity. If I try to change the optional parameter in the method implementation, it works directly, but the Unity object uses the interface's default - not the implemented method's default.

Setup:

public interface ITestOptional   {
     string HappyMethod(string input, bool amHappy = false);
}

public class TestingOptional : ITestOptional   {
     public string HappyMethod(string input, bool amHappy = true) {
                if (amHappy) return input + " is Happy!";
                return input + " is Not Happy!";
     }
}

Add to Unity:

container.RegisterType<ITestOptional, TestingOptional>();

And Test:

//direct call
var testDirect = new TestingOptional();
string happyDirect = testDirect.HappyMethod("Cow", true);  //expecting happy - get happy
string sadDirect = testDirect.HappyMethod("Cow", false);   //expecting not happy - get not happy
string defaultDirect = testDirect.HappyMethod("Cow"); //expecting happy (default) get happy

//unity
var testUnity = ServiceLocator.Current.GetInstance<ITestOptional>();

string happyUnity = testUnity.HappyMethod("Cow", true);  //expecting happy - get happy
string sadUnity = testUnity.HappyMethod("Cow", false);   //expecting not happy - get not happy
string defaultUnity = testUnity.HappyMethod("Cow"); //expecting happy (default) but get NOT happy.

Any ideas why the Unity object uses false as the optional parameter when the implementation uses true?

Upvotes: 2

Views: 2569

Answers (4)

Steven
Steven

Reputation: 172626

This has nothing to do with Unity. This is how C# compiler works. Optional arguments are filled in by the compiler at compile time. In the first example you call the HappyMethod method on the concrete type and that optional attribute is marked with true, so the C# compiler will fill in true for you. In the second example however, the C# compiler has no idea of the existence of the implementation, so it will look at the definition of the interface. And guess what: that interface is marked with false.

Upvotes: 1

Alex
Alex

Reputation: 13224

In your first example, your testDirect is an instance of type TestingOptional, for which you invoke its HappyMethod overload directly, using it's specified default parameter value of true.

In your second example, your testUnity is an instance of type ITestOptional and you invoke its HappyMethod that specifies a different default parameter value of false.

This is unrelated to how you created these instances. You would have observed the same if you had done:

ITestOptional x = new TestingOptional();
x.HappyMethod("Cow");

Upvotes: 0

Alexei Levenkov
Alexei Levenkov

Reputation: 100527

ServiceLocator.Current.GetInstance<ITestOptional>(); returns compile type ITestOptional, so call to testUnity.HappyMethod("Cow"); will be converted by compiler to use default value as specified in interface.

Similarly new TestingOptional(); returns compile time TestingOptional and compiler will pick default from the class.

Possible solution (short of adjusting expectations/not using different defaults): you can resolve that type directly using Unity instead of resolving interfce (sometimes useful for tests):

  var directViaContainer = container.Resolve<TestingOptional>();

Side note: re-defining default values in class implementing an interface is not a god practice - you'll get into this confusing code often.

Upvotes: 1

Felipe Oriani
Felipe Oriani

Reputation: 38598

You have to use the Resolve<T> method, from an IUnityContainer instance. For sample:

var testUnity = container.Resolve<ITestOptional>();

Upvotes: 0

Related Questions