Skip to content

Commit 1e49f89

Browse files
authored
Merge pull request #15 from azurefx/support_out_parameters
Support out parameters
2 parents 2f1b09a + 0f4599c commit 1e49f89

File tree

5 files changed

+74
-9
lines changed

5 files changed

+74
-9
lines changed

Artifacts.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[clrbridge]
2-
git-tree-sha1 = "a5d8e1de6e60b34ec42d252d2090965ccbca0022"
2+
git-tree-sha1 = "321e4d3676e1b4527c7d06dc6924869ef592662f"
33

44
[[clrbridge.download]]
5-
url = "https://github.com/azurefx/CLRBridge/releases/download/v0.1.2/CLRBridge.v0.1.2.tar.gz"
6-
sha256 = "3fa12f3432b7f22af7f6ace98b1fd9539580776368a3192189baedc8d72c4972"
5+
url = "https://github.com/azurefx/CLRBridge/releases/download/v0.1.3/CLRBridge.v0.1.3.tar.gz"
6+
sha256 = "500f0fcc267e14c6ccbe2703ffa7283ff1ca43c0a7e6bb4bd72f5d049364c614"

README.md

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,38 @@ julia> DotNET.unbox(s)
8989
""
9090
```
9191

92+
To pass an argument by reference (`out`/`ref` in `C#`), wrap it into a `Ref` object:
93+
94+
```julia
95+
julia> result = Ref{Int}()
96+
Base.RefValue{Int64}(212700848)
97+
98+
julia> T"System.Int64".TryParse("1970", result)
99+
true
100+
101+
julia> result[]
102+
1970
103+
104+
julia> result = Ref(null)
105+
Base.RefValue{CLRObject}(null)
106+
107+
julia> T"System.Int64".TryParse("2022", result)
108+
true
109+
110+
julia> result[]
111+
System.Int64(2022)
112+
```
113+
92114
### Arrays and Collections
93115

94116
To copy a multidimensional array from `.NET` to Julia, use `collect` method:
95117

96118
```julia
97-
julia> arr = convert(CLRObject, reshape(UnitRange{Int32}(1, 8), 2, 2, 2))
98-
System.Int32[,,]("System.Int32[,,]")
119+
julia> arr = convert(CLRObject, reshape(1:8, 2, 2, 2))
120+
System.Int64[,,]("System.Int64[,,]")
99121

100122
julia> collect(arr)
101-
2×2×2 Array{Int32, 3}:
123+
2×2×2 Array{Int64, 3}:
102124
[:, :, 1] =
103125
1 3
104126
2 4
@@ -110,8 +132,8 @@ julia> collect(arr)
110132

111133
CLI `Array` elements are stored in *row-major* order, thus the equivalent definition in `C#` is
112134
```csharp
113-
public static int[,,] Get3DArray() {
114-
return new int[2, 2, 2] {
135+
public static long[,,] Get3DArray() {
136+
return new long[2, 2, 2] {
115137
{{1, 2}, {3, 4}},
116138
{{5, 6}, {7, 8}}
117139
};

src/CLRBridge.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ empty_fp() = Ref{Ptr{Cvoid}}(0)
5151
const fp_Release = empty_fp()
5252
const fp_Duplicate = empty_fp()
5353
const fp_CreateArray = empty_fp()
54+
const fp_PutObject = empty_fp()
5455
const fp_PutString = empty_fp()
5556
const fp_GetString = empty_fp()
5657
const fp_FreeString = empty_fp()
@@ -101,6 +102,7 @@ function init(host::CLRHost)
101102
fp_Release[] = fp_primitive("Release")
102103
fp_Duplicate[] = fp_primitive("Duplicate")
103104
fp_CreateArray[] = fp_primitive("CreateArray")
105+
fp_PutObject[] = fp_primitive("PutObject")
104106
fp_PutString[] = fp_primitive("PutString")
105107
fp_GetString[] = fp_primitive("GetString")
106108
fp_FreeString[] = fp_primitive("FreeString")
@@ -152,6 +154,10 @@ function CreateArray(argc)
152154
track(ccall(fp_CreateArray[], Handle, (UInt32,), argc))
153155
end
154156

157+
function PutObject(handle, value)
158+
ccall(fp_PutObject[], Handle, (Handle, Handle), handle, value)
159+
end
160+
155161
function PutString(handle, value)
156162
ccall(fp_PutString[], Handle, (Handle, BStr), handle, value)
157163
end

src/marshalling.jl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,36 @@ box(x::Char, handle) = CLRBridge.PutChar(handle, x)
5757
boxedtype(::Type{Char}) = T"System.Char"
5858
box(x::String, handle) = CLRBridge.PutString(handle, x)
5959
boxedtype(::Type{String}) = T"System.String"
60+
box(x::Ref{CLRObject}, handle) = CLRBridge.PutObject(handle, gethandle(isassigned(x) ? x[] : CLRObject(0)))
61+
boxedtype(::Type{Ref{CLRObject}}) = boxedtype(CLRObject)
62+
box(x::Ref{T}, handle) where {T} = box(isassigned(x) ? x[] : Ref(CLRObject(0)), handle)
63+
boxedtype(::Type{Ref{T}}) where {T} = boxedtype(T)
6064

6165
function Base.convert(::Type{CLRObject}, x)
6266
CLRBridge.Duplicate(box(x, 1))
6367
end
6468

6569
Base.convert(::Type{CLRObject}, x::CLRObject) = x
6670

71+
function updateref(x::Ref{CLRObject}, handle)
72+
x[] = CLRBridge.Duplicate(handle)
73+
end
74+
75+
function updateref(x::Ref{T}, handle) where {T}
76+
x[] = unbox(CLRObject(handle))
77+
end
78+
6779
function invokemember(flags, type::CLRObject, this::CLRObject, name, args...)
6880
boxed = map(args, 1:length(args)) do arg, i
6981
box(arg, i)
7082
end
71-
unbox(CLRBridge.InvokeMember(gethandle(type), string(name), flags, 0, gethandle(this), boxed))
83+
ret = CLRBridge.InvokeMember(gethandle(type), string(name), flags, 0, gethandle(this), boxed)
84+
for (i, arg) in enumerate(args)
85+
if arg isa Ref
86+
updateref(arg, i)
87+
end
88+
end
89+
unbox(ret)
7290
end
7391

7492
function invokemember(type::CLRObject, this::CLRObject, name, args...)

test/runtests.jl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,25 @@ end
5555
t.Item1 = Int32(2)
5656
@test t.Item1 == Int32(2)
5757
end
58+
59+
# out parameters
60+
let
61+
tryparse(s, i) = T"System.Int64".TryParse(s, i)
62+
@test tryparse("42", null)
63+
@test !tryparse("abc", null)
64+
r = Ref{Int64}()
65+
@test !tryparse("abc", r)
66+
tryparse("123", r)
67+
@test r[] == 123
68+
r = Ref{CLRObject}()
69+
tryparse("def", r)
70+
@test unbox(r[]) == 0
71+
tryparse("456", r)
72+
@test unbox(r[]) == 456
73+
r = Ref{CLRObject}(1)
74+
tryparse("789", r)
75+
@test unbox(r[]) == 789
76+
end
5877
end
5978

6079
@testset "Generics" begin

0 commit comments

Comments
 (0)