You can do this with some interop code:
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
[return: MarshalAsAttribute(UnmanagedType.Bool)]
public static extern bool PathIsDirectory([MarshalAsAttribute(UnmanagedType.LPWStr), In] string pszPath);
To further clarify some of the comments...
Introducing unmanaged code in this is not any more inherintly dangerous than any of the other file or I/O related calls in .NET since they ultimatley all call in to unmanaged code.
This is a single function call using a string. You aren't introducing any new data types and/or memory usage by calling this function. Yes, you do need to rely on the unmanaged code to properly clean up, but you ultimately have that dependency on most of the I/O related calls.
For reference, here is the code to File.GetAttributes(string path) from Reflector:
public static FileAttributes GetAttributes(string path)
{
string fullPathInternal = Path.GetFullPathInternal(path);
new FileIOPermission(FileIOPermissionAccess.Read, new string[] { fullPathInternal }, false, false).Demand();
Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA();
int errorCode = FillAttributeInfo(fullPathInternal, ref data, false, true);
if (errorCode != 0)
{
__Error.WinIOError(errorCode, fullPathInternal);
}
return (FileAttributes) data.fileAttributes;
}
As you can see, it is also calling in to unmanaged code in order to retrieve the file attributes, so the arguements about introducing unmanaged code being dangerous are invalid. Likewise, the argument about staying completely in managed code. There is no managed code implementation to do this. Even calling File.GetAttributes() as the other answers propose have the same "issues" of calling unmanged code and I believe this is the more reliable method to accomplish determining if a path is a directory.
Edit To answer the comment by @Christian K about CAS. I believe the only reason GetAttributes makes the security demand is because it needs to read the properties of the file so it wants to make sure the calling code has permission to do so. This is not the same as the underlying OS checks (if there are any). You can always create a wrapper function around the P/Invoke call to PathIsDirectory that also demands certain CAS permissions, if necessary.