输入法开发中，下面的几个函数如果用C#改写，应该怎么写？
// edit session handling
STDMETHODIMP TextService::KeyEditSession::DoEditSession(TfEditCookie ec) {
	EditSession::DoEditSession(ec);
	return textService_->doKeyEditSession(ec, this);
}

// edit session handling
STDMETHODIMP TextService::StartCompositionEditSession::DoEditSession(TfEditCookie ec) {
	EditSession::DoEditSession(ec);
	return textService_->doStartCompositionEditSession(ec, this);
}

// edit session handling
STDMETHODIMP TextService::EndCompositionEditSession::DoEditSession(TfEditCookie ec) {
	EditSession::DoEditSession(ec);
	return textService_->doEndCompositionEditSession(ec, this);
}

// callback from edit session of key events
HRESULT TextService::doKeyEditSession(TfEditCookie cookie, KeyEditSession* session) {
	if(session->keyEvent_.type() == WM_KEYDOWN)
		session->result_ = onKeyDown(session->keyEvent_, session);
	else if(session->keyEvent_.type() == WM_KEYUP)
		session->result_ = onKeyUp(session->keyEvent_, session);
	return S_OK;
}

// callback from edit session for starting composition
HRESULT TextService::doStartCompositionEditSession(TfEditCookie cookie, StartCompositionEditSession* session) {
	ITfContext* context = session->context();
	ITfContextComposition* contextComposition;
	if(context->QueryInterface(IID_ITfContextComposition, (void**)&contextComposition) == S_OK) {
		// get current insertion point in the current context
		ITfRange* range = NULL;
		ITfInsertAtSelection* insertAtSelection;
		if(context->QueryInterface(IID_ITfInsertAtSelection, (void **)&insertAtSelection) == S_OK) {
			// get current selection range & insertion position (query only, did not insert any text)
			insertAtSelection->InsertTextAtSelection(cookie, TF_IAS_QUERYONLY, NULL, 0, &range);
			insertAtSelection->Release();
		}

		if(range) {
			if(contextComposition->StartComposition(cookie, range, (ITfCompositionSink*)this, &composition_) == S_OK) {
				// according to the TSF sample provided by M$, we need to reset current
				// selection here. (maybe the range is altered by StartComposition()?
				// So mysterious. TSF is absolutely overly-engineered!
				TF_SELECTION selection;
				selection.range = range;
				selection.style.ase = TF_AE_NONE;
				selection.style.fInterimChar = FALSE;
				context->SetSelection(cookie, 1, &selection);
				// we did not release composition_ object. we store it for use later
			}
			range->Release();
		}
		contextComposition->Release();
	}
	return S_OK;
}

// callback from edit session for ending composition
HRESULT TextService::doEndCompositionEditSession(TfEditCookie cookie, EndCompositionEditSession* session) {
	if(composition_) {
		// move current insertion point to end of the composition string
		ITfRange* compositionRange;
		if(composition_->GetRange(&compositionRange) == S_OK) {
			// clear display attribute for the composition range
			ComPtr<ITfProperty> dispAttrProp;
			if(session->context()->GetProperty(GUID_PROP_ATTRIBUTE, &dispAttrProp) == S_OK) {
				dispAttrProp->Clear(cookie, compositionRange);
			}

			TF_SELECTION selection;
			ULONG selectionNum;
			if(session->context()->GetSelection(cookie, TF_DEFAULT_SELECTION, 1, &selection, &selectionNum) == S_OK) {
				selection.range->ShiftEndToRange(cookie, compositionRange, TF_ANCHOR_END);
				selection.range->Collapse(cookie, TF_ANCHOR_END);
				session->context()->SetSelection(cookie, 1, &selection);
				selection.range->Release();
			}
			compositionRange->Release();
		}
		// end composition and clean up
		composition_->EndComposition(cookie);
		// do some cleanup in the derived class here
		onCompositionTerminated(false);
		composition_->Release();
		composition_ = NULL;
	}
	return S_OK;
}