I have the following generic type with a generic type constraint.
public class GenericType<T> where T: IFoo
{
}
Then I try to create a closed generic type from the open generic type.
var fooGenericType = typeof(GenericType<>).MakeGenericType (typeof(IFoo));
var intGenericType = typeof(GenericType<>).MakeGenericType (typeof(int));
When running in the simulator it fails on trying to create a closed generic type using an int as the type parameter which is expected.
BUT, when running on the actual device (iPhone), it will also create a closed generic type using an int.
It seems like it does not respect the generic constraint, but this happens only on the device. On the simulator everything is as expected.
Any ideas?
This seems to be related to the fact that MonoTouch uses AoT compilation. It causes some limitations regarding generic types, as pointed here
Like William Barbosa mentioned there are limitations regarding generic types on iOS.
The linker excludes combinations of generic types with several parameters when it thinks they are not necassary. As the simulator is a different build target the linker might work differently.
You can force the linker to include a generic type with specific type parameters by using them anywhere in your code.
A common way is to provide a LinkerPleaseInclude.cs file like here: https://github.com/MvvmCross/MvvmCross-Tutorials/blob/master/DailyDilbert/DailyDilbert.Touch/LinkerPleaseInclude.cs
It's also pointed out here: MakeGenericMethod/MakeGenericType on Xamarin.iOS
Related
I have experienced the following problem while writing a test. Please find a picture bellow.
If I create validateGameExistance function in the unit test project then it works fine.
How could it be solved?
It is hard to give a definite answer (based just on the screenshot), but you can get this kind of error when some of the types involved in the type error are defined in multiple places (so, the type name would look the same, but they would actually be different types in different assemblies).
For example, if the Result<T> type is defined in multiple projects and the function you're calling returns one of them, but your annotation is referring to another one.
I have a union type that has a single, empty case.
type Default =
| Default
This type has a purpose, but it's not meant to be visible or usable.
Unfortunately, I have to use it in an inline function that does need to be visible. This prevents me from making the type or the case private.
The solution I came up with is using the CompilerMessageAttribute on it to signal an error whenever it's used. This would be fine, but now I can't compile my own assembly because IT uses it.
Is there a way to signal an error only when it's used by an assembly that references my assembly?
Let me reiterate the requirements to make sure I understand them:
The type needs to be public, so that that other assemblies can reference it implicitly via inline.
But if other assemblies reference it explicitly, then that is an error.
I don't know of any way of doing this using standard tooling.
I can see two possible solutions.
If only one calling assembly needs to use the inline function, what about making the type internal and then have the calling assembly be a friend assembly, using the InternalsVisibleToAttribute.
The only other alternative I can think of is security by obscurity. Hide the type in some awkwardly named module and require module qualification. This will stop accidental use of the type, if nothing else.
You could even add a build step to check that no source code references the module name.
[<RequireQualifiedAccessAttribute>]
module ``Dont Use This`` =
type Default =
| Default
let x = ``Dont Use This``.Default
And yes, it's very kludgy.
I am very confused on the MonoTouch dictionary limitation: http://docs.xamarin.com/ios/about/limitations#Value_types_as_Dictionary_Keys
My understanding that code like this is not allowed:
var foo = new Dictionary<int, int>();
But I see code in books like this, which doesn't make sense:
protected Dictionary<int, CustomCellController> _cellControllers = new Dictionary<int, CustomCellController>();
Also, someone posted that if you use nullable types, it convers the values into reference so the following works (as long as the key is not null):
var foo = new Dictionary<int?, int?>();
That also doesn't make sense, because nullable types are structs which are value types.
So what are the real rules about using dictionaries on a device?
Since no JITin is allowed on devices all code must be compiled with the AOT (ahead of time) compiler.
My understanding that code like this is not allowed:
This limitation is about the difficulties, for the AOT compiler, of determining what will be used at runtime. Such code might work and you'll see such code in samples - but it can also fail depending on what you do with the code (creating a Dictionary is not the problem).
So what are the real rules about using dictionaries on a device?
Using value-types means that the generated code cannot be shared (like it can for reference types). E.g. Using a generic Dictionary with int and long requires separate code, while the same code can be shared for string and CustomCellController.
Finding what Dictionary<int,int> needs is not the issue (it's pretty clear). However it's often in the internals that things gets complicated, e.g. ensuring the right KeyValuePair is generated. Nested generics are also hard to get right.
This is why the first general workaround is to try to hint the AOT compiler about what's needed. If the AOT compiler can find code that requires it to generate what's needed then it will be available at runtime.
The next workaround is to try to use a reference type (e.g. a string) instead of the value-type (since that case is simpler to handle for the AOT compiler).
Finally the AOT compiler is getting better (by each release) and works continues to reduce this (and other) limitation(s). So what you read here might not apply in 3, 6, 12 months...
I apologize for such a long message in advance, but I'm trying for detail here...
I'm working on using bTouch to create a compiled dll for referencing the ArcGIS iOS SDK.
When running bTouch using :
/Developer/MonoTouch/usr/bin/btouch libArcGIS.cs
it returns the following error
/tmp/fp2ivuh8.3gj/IncidentReportApp/AGSMutablePolygon.g.cs(39,31):
error CS0102: The type `IncidentReportApp.AGSMutablePolygon'
already contains a definition for `selAddPointToRing'
/tmp/fp2ivuh8.3gj/IncidentReportApp/AGSMutablePolygon.g.cs(38,31):
(Location of the symbol related to previous error)
/tmp/fp2ivuh8.3gj/IncidentReportApp/AGSMutablePolyline.g.cs(39,31): error CS0102:
The type `IncidentReportApp.AGSMutablePolyline'
already contains a definition for `selAddPointToPath'
/tmp/fp2ivuh8.3gj/IncidentReportApp/AGSMutablePolyline.g.cs(38,31):
(Location of the symbol related to previous error)
Compilation failed: 2 error(s), 0 warnings
I checked my cs class and neither type is referenced\invoked. I'd like to understand why this message is occuring.
I have tried to use the instructions (and downloaded) code by Al Pascual at How to use the ArcGIS iPhone SDK with MonoTouch to call the Map View, but when attempting to launch the view with the code causes a crash. When I try to debug, it locks up when adding a mapping layer. I tested this with the MKMapView, but didn't experience the same behavior.
The error means that you defined more than one method mapping the same objective-C method.
Without the source, it is hard to diagnose.
I'm doing the same thing actually, I heavily modified the old "parser" library and am working on doing it now, hopefully dropping it in the public domain.
I'm seeing a similar (and probably related) problem in the ApiDefinition, there is a class AGSGPResultLayer that derives from AGSDynamicLayer. The AGSGPResultLayer overrides a property called Credential among other and since both are defining the same property.
How should over-riden properties be handled in bTouch? I'm guessing I'm missing something in the syntax.
Use the solution I provide with the correct bindings
I tried following the example given on MSDN, but my code does not compile on the compact framework. It does compile on the normal framework, though.
type StorageComponent(game) =
inherit GameComponent(game)
let title_storage_acquired_event = new Control.DelegateEvent<StorageEventHandler>()
Error message:
The type 'DelegateEvent' is not defined
Based on the hint from Brian, it looks that the types DelegateEvent<'Delegate> and Event<'Delegate, 'Args> are not supported on .NET Compact Framework. This would mean that you cannot declare an event that uses an explicitly specified delegate type.
However, you can still use the Event<'T> type which creates an event of type Handler<'T> (which is a generic delegate type representing methods with two parameters of types obj and 'T):
type StorageComponent(game) =
inherit GameComponent(game)
let titleStorageAcquiredEvent =
new Event<StorageEventArgs>()
[<CLIEvent>] // If you want to create C# compatible event
member x.TitleStorageAcquired =
titleStorageAcquiredEvent.Publish()
Assuming that the declaration of StorageEventHandler looks like this:
delegate void StorageEventHandler(object sender, StorageEventArgs args);
The example above should create more or less an equivalent code (with the only difference that it uses generic Handler<_> delegate type instead of your own StorageEventHandler).
If you take a look at the code in the CTP
C:\Program Files (x86)\FSharp-2.0.0.0\source\fsharp\FSharp.Core\event.fs
it will offer some clues (I'm guessing NETCF does not have del.DynamicInvoke). It might also offer clues as to what to do instead; I'm not sure, but hopefully someone else will chime in with a full answer.