Mavlink code wants to do everything. What happens is you get some raw data in and you pass that packet of data to Mavlink and it does it thing looking for stuff that matches and then builds a Message.
The then does a call to your function with this decoded packed and you need to cast it back to the right packet.
Things get a little strange with C# since it doesn't like you playing around with binary data and then stuffing it into and object. The C version is a little more straight forward but works the same.
To send Mavlink packets you fill in the object you want to send and it will build and send the packet or you can use the build function to just build the packet and you have to convert it to a serial object to send.
It's been a while since I did this and it took some time to understand what was happening.
Here is a GitHub sample that reads from a com port: MavlinkReader
It's from a couple of year ago so the Mavlink libraries are not up to date.