Rotate List by K places
if (k &gt; 0 &amp;&amp; head != null) {
            ...
            return RotatedList;

        }

        return head;



would be clearer (and more consistent with the other special case) as

        if (k &lt;= 0 || head == null) {
            return head;
        }

        ...
        return RotatedList;


(although really if k &lt; 0 I think it should throw new ArgumentOutOfRangeException(nameof(k))).




            ListNode tail = head,
            RotatedList = null,
            kthnode = head,
            kthPrevNode = head;



Most of these don't need to be declared so early. Declaring variables as late as possible (and, more generally, in the narrowest scope possible) helps to reduce cognitive load when maintaining the code.




            int listLength = 0;
            while (tail != null) {
                listLength += 1;
                tail = tail.next;
            }



This would be worth factoring out as a separate method Length(ListNode head).




            k = k % listLength;
            if (k == 0 || listLength == 0) {
                return head;
            }



This is sort-of buggy. If listLength == 0 then k % listLength will throw an ArithmeticException. However, you can never reach here in that case, because listLength == 0 is equivalent to head == null, and that was already handled in the first special case. To remove confusion, delete || listLength == 0. If you want to validate that condition, insert System.Diagnostics.Debug.Assert(listLength &gt; 0); before the % line.




            for (int i = 0; i &lt; listLength - k; i++) {

                kthPrevNode = kthnode;

                kthnode = kthnode.next;

            }



It's not actually necessary to track two nodes here. The invariant is that kthPrevNode.next == kthnode, so it suffices to track kthPrevNode.

Also, the blank lines seem excessive to me.




            RotatedList = kthnode;



It's conventional in C# that local variable names start with a lower case letter, so to avoid confusion I would rename RotatedList to rotatedList (or perhaps rotatedHead).



There are only two things where I can see that the efficiency can be improved: one is eliminating kthnode in the loop, as commented above; the other would be to hang on to the last node when finding the length, so that you don't need to find it a second time in the last few lines. (That would imply changing the factored out method to return an (int, ListNode) tuple).

As for time complexity, it's already optimal: linear time. Good job!