Can someone explain the magic going on in Prism's resolve<> method? - wpf

I've got a CustomersModule.cs with the following Initialize() method:
public void Initialize()
{
container.RegisterType<ICustomersRepository, CustomersRepository>(new ContainerControlledLifetimeManager());
CustomersPresenter customersPresenter = this.container.Resolve<CustomersPresenter>();
}
The class I resolve from the container looks like this:
class CustomersPresenter
{
private CustomersView view;
private ICustomersRepository customersRespository;
public CustomersPresenter(CustomersView view,
ICustomersRepository customersRepository,
TestWhatever testWhatever)
{
this.view = view;
this.customersRespository = customersRepository;
}
}
The TestWhatever class is just a dummy class I created:
public class TestWhatever
{
public string Title { get; set; }
public TestWhatever()
{
Title = "this is the title";
}
}
Yet the container happily resolves CustomersPresenter even though I never registered it, and also the container somehow finds TestWhatever, instantiates it, and injects it into CustomersPresenter.
I was quite surprised to realize this since I couldn't find anywhere in the Prism documentation which explicitly stated that the container was so automatic.
So this is great, but it what else is the container doing that I don't know about i.e. what else can it do that I don't know about? For example, can I inject classes from other modules and if the modules happen to be loaded the container will inject them, and if not, it will inject a null?

There is nothing magical going on. You are specifying concrete types, so naturally they are resolvable, because if we have the Type object, we can call a constructor on it.
class Fred { };
Fred f1 = new Fred();
Type t = typeof(Fred);
Fred f2 = (Fred)t.GetConstructor(Type.EmptyTypes).Invoke(null);
The last line above is effectively what happens, the type t having been found by using typeof on the type parameter you give to Resolve.
If the type cannot be constructed by new (because it's in some unknown separate codebase) then you wouldn't be able to give it as a type parameter to Resolve.
In the second case, it is constructor injection, but it's still a known concrete constructable type. Via reflection, the Unity framework can get an array of all the Types of the parameters to the constructor. The type TestWhatever is constructable, so there is no ambiguity or difficulty over what to construct.
As to your concern about separate modules (assemblies), if you move TestWhatever to another assembly, that will not change the lines of code you've written; it will just mean that you have to add a reference to the other assembly to get this one to build. And then TestWhatever is still an unambiguously refeferenced constructable type, so it can be constructed by Unity.
In other words, if you can refer to the type in code, you can get a Type object, and so at runtime it will be directly constructable.
Response to comment:
If you delete the class TestWhatever, you will get a compile-time error, because you refer to that type in your code. So it won't be possible to get a runtime by doing that.
The decoupling is still in effect in this arrangement, because you could register a specific instance of TestWhatever, so every call to Resolve<TestWhatever>() will get the same instance, rather than constructing a new one.

The reason this works is because Unity is designed for it. When you Resolve with a concrete type, Unity looks to see if it can resolve from the container. If it cannot, then it just goes and instantiates the type resolving it's dependencies. It's really quite simple.

Related

Why use Func<> in controller constructor parameters in MVVM applications

I'm seeing, more and more code like the code below in an MVVM application (WPF and Prism). Controllers have the following code fragments:
public class DispenseOptionController : IDispenseOptionController
{
protected readonly Func<IPharmacyCdmServiceSimpleClient> CdmClient;
protected readonly Func<IPatientServiceSimpleClient> PatientClient;
public DispenseOptionController(Func<IPharmacyCdmServiceSimpleClient> cdmClient, Func<IPatientServiceSimpleClient> patientClient)
{
CdmClient = cdmClient;
PatientClient = patientClient;
}...
I'm trying to understand the role that Func<> plays here. It seems that this delegate is used as parameters to the constructor. Can someone explain to me why anyone would use Func<> in this particular case? And can Func<> be replaced with anything else?
A Func<> is nothing but the Encapsulation of a method that one or more parameter and returns a value of the type specified by the TResult parameter.
You could see some use cases here

from VBS to WPF via COM

we have a nasty (or maybe a trivial?) issue.
There is a WPF control. It has 2 interfaces, the main and one for automated testing purpose. Defined this way:
[ComVisible(true)]
[Guid("xxx")]
public interface IXXXXXTest
{
[DispId(1)]
void Test1(int index);
}
[ComVisible(true)]
public interface IXXXXX
{
void Main1(index);
}
[ComVisible(true)]
[Guid("xxx")]
ClassInterface(ClassInterfaceType.None)]
public partial class XXXXX_WPF_CONTROL : UserControl,
IXXXXX,
IXXXXXTest
{
...
}
Now we are trying to reach it from VBS.
Try 1)
Set Ctrl = GetControl(...) <---- this is ok
Ctrl.Test1(0) <---- Object doesn't support this property or method: 'Ctrl.Test1'
Set Ctrl = GetControl(...) <---- this is ok
Ctrl.Main1(0) <---- this is ok
So it works fine for the "main" interface but for the test interface.
This seems ok(?), because as far as I know VBS reaches the "main" interface only via IDispatch if there is no IDispatchEx. So I added a property to the IXXXXX to get the test interface.
[ComVisible(true)]
public interface IXXXXX
{
void Main1(index);
IXXXXXTest Test { get;}
}
....
public IXXXXXTest Test
{
get { return this as IXXXXXTest; }
}
Great, so now I can reach this IXXXXTest interface via the "main" interface.
Try 2)
VBS:
Set Ctrl = GetControl(...) <---- this is ok
Set CtrlTest = Ctrl.Test <----- this is ok
CtrlTest.Test1(0) <---- Object doesn't support this property or method: 'CtrlTest.Test1'
:(
Note that, for an other .NET control of us the "Try1" works, without any trick!
So probably due to the WPF something different?
Also, changing the
ClassInterface(ClassInterfaceType.None)]
into anything else (AutoDispatch / AutoDual), or leaving it makes the WPF control unusable.
Besides that this is also how it should be by this article: Is it possible to package WPF window as COM Object
Do you have any idea what could be the problem?
Thank much in advance!
Scripting languages can only use the default interface on a class. You've got more than one so at least one of them will not be usable. And method names may be renamed if they conflict with other declarations. I'd assume you obfuscated the real names in your question so hard to diagnose such a renaming happening from what you posted.
Best thing to do is to temporarily apply the [InterfaceType(ComInterfaceType.InterfaceIsDual)] attribute on your interface types. Which allows you to generate a type library with Tlbexp.exe which you can then view with the OleView.exe utility, File + View Typelib command. You'll see the exact names of the methods and you'll see which interface is the [default] one on the coclass. From there you should have little trouble modifying your declarations so they'll work in a scripting language.

Error Application cast in WPF

i have 2 projects in my solution (main is A.WPF and secondary is B.WPF)
when i'm trying to access variables inside my App.xaml.cs in B.WPF:
filename = ((App)Application.Current).ErrorLogFileName;
i get the following error:
Unable to cast object of type 'A.App' to type 'B.App'.
i also tried the following:
filename = ((B.App)Application.Current).ErrorLogFileName;
but still the same error...
the definition in B.App is:
private string _errorLogFileName = "error log.xml";
public string ErrorLogFileName
{
get { return _errorLogFileName; }
}
please assist...
Looks like you need to do:
filename = ((A.App)Application.Current).ErrorLogFileName;
The error is saying the type is A.App, yet in both cases you are trying to cast to B.App.
There can only be one current application also.
Application.Current refers to the current application. The only way to be allowed to cast the current App to another App-type is when the other App-type is a base class of the current App-type.
Are A.App and B.App siblings or is B.App a base class of A.App?
If you don't want B to have a reference to A (or can't as you want A to reference B and that would cause a circular reference), then you need a common type defined in a third assembly that both A and B reference. In our implementation we tend to have a ConfigurationData type that is in a separate project referenced by both Wpf projects, e.g.
public static class ConfigurationData
{
private static string _errorLogFileName = "error log.xml";
public string ErrorLogFileName
{
get { return _errorLogFileName; }
}
}
Another approach would be to define an Interface for your ErrorLogFileName property in a 3rd assembly that both A and B reference, and then implement that interface on your Wpf Application class - A and B would then both be able to cast to that type. If you wanted your A project to set the values on that at runtime, you could make the ErrorLogFileName a read-write property instead and initialize it in your application startup.
I personally prefer using a separate ConfigurationData type from the Wpf app object for this kind of stuff (ErrorLogFileName etc.) as it can then also be used for code that might execute in a unit test and therefore might not be running under a Wpf application - it also avoids having to do casts all over the place (ConfigurationData.ErrorLogFileName instead of ((IAppConfigurationData)Application.Current).ErrorLogFileName.
BTW, if you have an Application object in both assemblies it sounds like you might have both assemblies configured to build as Output type: Windows Application in your project properties. You should only really have one assembly that is configured as the Windows Application and the rest should be Class Library to avoid confusing numbers of Application classes being generated - only the one in the main EXE (and it's related resources) will get created at runtime.

Creating New Array with Class Object in GWT

I would like to create a new array with a given type from a class object in GWT.
What I mean is I would like to emulate the functionality of
java.lang.reflect.Array.newInstance(Class<?> componentClass, int size)
The reason I need this to occur is that I have a library which occasionally needs to do the following:
Class<?> cls = array.getClass();
Class<?> cmp = cls.getComponentType();
This works if I pass it an array class normally, but I can't dynamically create a new array from some arbitrary component type.
I am well aware of GWT's lack of reflection; I understand this. However, this seems feasible even given GWT's limited reflection. The reason I believe this is that in the implementation, there exists an inaccessible static method for creating a class object for an array.
Similarly, I understand the array methods to just be type-safe wrappers around JavaScript arrays, and so should be easily hackable, even if JSNI is required.
In reality, the more important thing would be getting the class object, I can work around not being able to make new arrays.
If you are cool with creating a seed array of the correct type, you can use jsni along with some knowledge of super-super-source to create arrays WITHOUT copying through ArrayList (I avoid java.util overhead like the plague):
public static native <T> T[] newArray(T[] seed, int length)
/*-{
return #com.google.gwt.lang.Array::createFrom([Ljava/lang/Object;I)(seed, length);
}-*/;
Where seed is a zero-length array of the correct type you want, and length is the length you want (although, in production mode, arrays don't really have upper bounds, it makes the [].length field work correctly).
The com.google.gwt.lang package is a set of core utilities used in the compiler for base emulation, and can be found in gwt-dev!com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang.
You can only use these classes through jsni calls, and only in production gwt code (use if GWT.isProdMode()). In general, if you only access the com.google.gwt.lang classes in super-source code, you are guaranteed to never leak references to classes that only exist in compiled javascript.
if (GWT.isProdMode()){
return newArray(seed, length);
}else{
return Array.newInstance(seed.getComponentType(), length);
}
Note, you'll probably need to super-source the java.lang.reflect.Array class to avoid gwt compiler error, which suggests you'll want to put your native helper method there. However, I can't help you more than this, as it would overstep the bounds of my work contract.
The way that I did a similar thing was to pass an empty, 0 length array to the constructor of the object that will want to create the array from.
public class Foo extends Bar<Baz> {
public Foo()
{
super(new Baz[0]);
}
...
}
Baz:
public abstract class Baz<T>
{
private T[] emptyArray;
public Baz(T[] emptyArray)
{
this.emptyArray = emptyArray;
}
...
}
In this case the Bar class can't directly create new T[10], but we can do this:
ArrayList<T> al = new ArrayList<T>();
// add the items you want etc
T[] theArray = al.toArray(emptyArray);
And you get your array in a typesafe way (otherwise in your call super(new Baz[0]); will cause a compiler error).
I had to do something similar, I found it was possible using the Guava library's ObjectArrays class. Instead of the class object it requires a reference to an existing array.
T[] newArray = ObjectArrays.newArray(oldArray, oldArray.length);
For implementing an array concatenation method, I also stepped into the issue of missing Array.newInstance-method.
It's still not implemented, but if you have an existing array you can use
Arrays.copyOf(T[] original, int newLength)
instead.

What use has RoutedCommand' class constructor ownertype argument?

The constructor of the RoutedCommand has "owner type" as a last argument. What is its significance? When it is used?
MSDN documentation gives completely no clue about why it's needed and whether I could use one type for all commands
Quote from MSDN
ownerType
Type: System.Type The type
which is registering the command.
There is one more thing. What type should I use when creating new routed commands dynamically from array of names. It looks like that any type works, so I'm using UIElement, but if there is a more suited type for this I would like to know.
The source for RoutedCommand shows that the type becomes the OwnerType property. This property is queried ultimately by the following private method when getting InputGestures. So it looks as though this type is being used to lookup a (hard-coded) set of Commands based on the type that created the RoutedCommand.
private InputGestureCollection GetInputGestures()
{
if (this.OwnerType == typeof(ApplicationCommands))
{
return ApplicationCommands.LoadDefaultGestureFromResource(this._commandId);
}
if (this.OwnerType == typeof(NavigationCommands))
{
return NavigationCommands.LoadDefaultGestureFromResource(this._commandId);
}
if (this.OwnerType == typeof(MediaCommands))
{
return MediaCommands.LoadDefaultGestureFromResource(this._commandId);
}
if (this.OwnerType == typeof(ComponentCommands))
{
return ComponentCommands.LoadDefaultGestureFromResource(this._commandId);
}
return new InputGestureCollection();
}
I know this is a very old question, but it's the top search hit for "routedcommand ownertype".
Storing an OwnerType and Name within each RoutedCommand object gives you a hint on how to find references to it in code. Suppose you are running the debugger on some method that has an arbitrary ICommandSource parameter. You can examine the Command property, and if you see that OwnerType is CommonCommands and Name is "DoSomething", you can navigate to the DoSomething field of the CommonCommands class, where there might be a useful comment, or search for references to CommonCommands.DoSomething to find associated CommandBindings or something. Without those properties, the RoutedCommand would just be an anonymous object.
I don't know if that reason was what the API designers actually had in mind when they included the argument, but it has been useful to me at least.

Resources