This package provides interoperability between Julia and Common Language Runtime, the execution engine of .NET applications. Many languages run on CLR, including C#, Visual Basic .NET and PowerShell.
Juliaversion 1.3+.NET Core Runtimeversion 2.2+ (Download)
WinForms and other GUI-related features require a desktop runtime.
If the package fails to locate the runtime, set DOTNET_ROOT environment variable to the path containing the dotnet or dotnet.exe binary.
.NET Framework is not supported yet.
In the REPL, type ]add DotNET and press Enter.
(v1.x) pkg> add DotNET
Or use Pkg.add for more options:
julia> using Pkg
julia> Pkg.add(PackageSpec(url = "https://github.com/azurefx/DotNET.jl"))julia> using DotNETDotNET.jl provides the T"AssemblyQualifiedTypeName" literal for type reference:
julia> Console = T"System.Console, mscorlib"
System.ConsoleGiven a type object, you can access its properties or methods using the dot operator:
julia> Console.WriteLine("Hello from .NET!");
Hello from .NET!To create an object, use the new syntax:
julia> T"System.Guid".new("CA761232-ED42-11CE-BACD-00AA0057B223")
System.Guid("ca761232-ed42-11ce-bacd-00aa0057b223")All .NET objects are represented by CLRObjects in Julia, including types:
julia> typeof(Console)
CLRObject
julia> typeof(null)
CLRObjectnull is a built-in object that does not refer to a valid .NET object. When you try to access a member on a null value, a System.NullReferenceException is thrown.
Arguments passed to .NET methods are automatically converted to CLRObjects, and return values are converted to corresponding Julia types:
julia> T"System.Convert".ToInt64("42")
42Or you could do some explicit conversions:
julia> s = convert(CLRObject, "❤")
System.String("❤")
julia> DotNET.unbox(s)
"❤"To pass an argument by reference (out/ref in C#), wrap it into a Ref object:
julia> result = Ref{Int}()
Base.RefValue{Int64}(212700848)
julia> T"System.Int64".TryParse("1970", result)
true
julia> result[]
1970
julia> result = Ref(null)
Base.RefValue{CLRObject}(null)
julia> T"System.Int64".TryParse("2022", result)
true
julia> result[]
System.Int64(2022)To copy a multidimensional array from .NET to Julia, use collect method:
julia> arr = convert(CLRObject, reshape(1:8, 2, 2, 2))
System.Int64[,,]("System.Int64[,,]")
julia> collect(arr)
2×2×2 Array{Int64, 3}:
[:, :, 1] =
1 3
2 4
[:, :, 2] =
5 7
6 8CLI Array elements are stored in row-major order, thus the equivalent definition in C# is
public static long[,,] Get3DArray() {
return new long[2, 2, 2] {
{{1, 2}, {3, 4}},
{{5, 6}, {7, 8}}
};
}To index into arrays, use arraystore and arrayload methods. Note that CLI Arrays use zero-based indexing.
julia> DotNET.arraystore(arr, (1, 1, 1), 0)
null
julia> DotNET.arrayload(arr, (1, 1, 1)) == collect(arr)[2, 2, 2]
trueIf an object implements IEnumerable interface, you can call GetEnumerator to iterate over the array:
julia> ch = Channel() do it
e = arr.GetEnumerator()
while e.MoveNext()
put!(it, e.Current)
end
end
Channel{Any}(0) (1 item available)
julia> collect(ch)
8-element Vector{Any}:
1
⋮
8Or just use the for-in loop:
for x in arr
println(x)
endIf you have a DLL file, you can load it using reflection:
julia> T"System.Reflection.Assembly".LoadFrom(raw"C:\Users\Azure\Desktop\test.dll")
System.Reflection.RuntimeAssembly("test, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")Now you have access to types defined in the assembly.
Generic types are be expressed in the following ways:
julia> ListT = T"System.Collections.Generic.List`1"
System.Collections.Generic.List`1[T]
julia> ListInt64 = T"System.Collections.Generic.List`1[System.Int64]"
System.Collections.Generic.List`1[System.Int64]The number 1 after the backtick indicates the type System.Collections.Generic.List<T> has one type parameter. ListT has a free type variable, just like Vector{T} where T in Julia. A type that includes at least one type argument is called a constructed type. ListInt64 is a constructed type.
One can substitute type variables and make a constructed type by calling makegenerictype method:
julia> DotNET.makegenerictype(ListT, T"System.String")
System.Collections.Generic.List`1[System.String]To invoke a generic method, put type arguments into square brackets:
julia> list = ListT.new[T"System.Int64"]()
System.Collections.Generic.List`1[System.Int64]("System.Collections.Generic.List`1[System.Int64]")To create a delegate from a Julia method, use delegate method:
julia> list = ListT.new[T"System.Int64"](1:5)
System.Collections.Generic.List`1[System.Int64]("System.Collections.Generic.List`1[System.Int64]")
julia> list.RemoveAll(delegate(iseven, T"System.Predicate`1[System.Int64]"))
2
julia> collect(list)
3-element Vector{Int64}:
1
3
5