First of all, you don't do sh -c "echo $1 - $2 - $3" because the double-quotes will cause your current shell to expand $1, $2 and $3. Even if you managed to set these in the current shell beforehand, it still wouldn't be a good general way because the result of the expansion would be interpreted by sh as shell code. Unless you want it to be interpreted as shell code, don't do this.
xargs -Iline sh -c "sh dummy.sh line" is similarly flawed: line will be interpreted by the outer sh. What if it happens to be ; rm -f /important/file or $(shutdown)? It's like embedding {}. Don't.
If you want to provide some values, provide as arguments to the sh itself:
<dummy.dat xargs -n3 sh -c 'echo "$1 - $2 - $3"' sh
The second sh is explained here: What is the second sh in sh -c 'some shell code' sh? The single-quotes protect $1, $2 and $3 from being expanded by the current shell. sh gets the shell code exactly as it is within the single-quotes: echo "$1 - $2 - $3". Arbitrary strings are passed as arguments, expanded only by sh, there is no code injection vulnerability.