As part of writing up notes for introducing F# as a programming language to experienced C# devs I was looking for examples
of heavily OO code being implemented in F#. Then I realised that I'd written at least one suitable example myself.
In the NuGetPlus project I needed to implement a ProjectSystem class that was almost a direct copy of the MSBuildProjectSystem in the NuGet commandline client.
So without further ado, F# and then C# versions of a class with inheritance and which implements several interfaces.
usingSystem;usingSystem.Collections.Generic;usingSystem.IO;usingSystem.Linq;usingSystem.Reflection;usingSystem.Runtime.Versioning;usingMicrosoft.Build.Evaluation;namespaceNuGet.Common{publicclassMSBuildProjectSystem:PhysicalFileSystem,IMSBuildProjectSystem{publicMSBuildProjectSystem(stringprojectFile):base(Path.GetDirectoryName(projectFile)){Project=GetProject(projectFile);}publicboolIsBindingRedirectSupported{get{returntrue;}}privateProjectProject{get;set;}publicvoidAddFrameworkReference(stringname){// No-op}publicvoidAddReference(stringreferencePath,Streamstream){stringfullPath=PathUtility.GetAbsolutePath(Root,referencePath);stringrelativePath=PathUtility.GetRelativePath(Project.FullPath,fullPath);// REVIEW: Do we need to use the fully qualified the assembly name for strong named assemblies?stringinclude=Path.GetFileNameWithoutExtension(fullPath);Project.AddItem("Reference",include,new[]{newKeyValuePair<string,string>("HintPath",relativePath)});}publicdynamicGetPropertyValue(stringpropertyName){returnProject.GetPropertyValue(propertyName);}publicboolIsSupportedFile(stringpath){returntrue;}publicstringProjectName{get{returnPath.GetFileNameWithoutExtension(Project.FullPath);}}publicboolReferenceExists(stringname){returnGetReference(name)!=null;}publicvoidRemoveReference(stringname){ProjectItemassemblyReference=GetReference(name);if(assemblyReference!=null){Project.RemoveItem(assemblyReference);}}privateIEnumerable<ProjectItem>GetItems(stringitemType,stringname){returnProject.GetItems(itemType).Where(i=>i.EvaluatedInclude.StartsWith(name,StringComparison.OrdinalIgnoreCase));}publicProjectItemGetReference(stringname){name=Path.GetFileNameWithoutExtension(name);returnGetItems("Reference",name).FirstOrDefault(item=>newAssemblyName(item.EvaluatedInclude).Name.Equals(name,StringComparison.OrdinalIgnoreCase));}publicFrameworkNameTargetFramework{get{stringmoniker=GetPropertyValue("TargetFrameworkMoniker");if(String.IsNullOrEmpty(moniker)){returnnull;}returnnewFrameworkName(moniker);}}publicstringResolvePath(stringpath){returnpath;}publicvoidSave(){Project.Save();}publicboolFileExistsInProject(stringpath){// some ItemTypes which starts with _ are added by various MSBuild tasks for their own purposes// and they do not represent content files of the projects. Therefore, we exclude them when checking for file existence.returnProject.Items.Any(i=>i.EvaluatedInclude.Equals(path,StringComparison.OrdinalIgnoreCase)&&(String.IsNullOrEmpty(i.ItemType)||i.ItemType[0]!='_'));}privatestaticProjectGetProject(stringprojectFile){returnProjectCollection.GlobalProjectCollection.GetLoadedProjects(projectFile).FirstOrDefault()??newProject(projectFile);}publicvoidAddImport(stringtargetPath,ProjectImportLocationlocation){if(targetPath==null){thrownewArgumentNullException("targetPath");}// adds an <Import> element to this project file.if(Project.Xml.Imports==null||Project.Xml.Imports.All(import=>!targetPath.Equals(import.Project,StringComparison.OrdinalIgnoreCase))){Project.Xml.AddImport(targetPath);NuGet.MSBuildProjectUtility.AddEnsureImportedTarget(Project,targetPath);Project.ReevaluateIfNecessary();Project.Save();}}publicvoidRemoveImport(stringtargetPath){if(targetPath==null){thrownewArgumentNullException("targetPath");}if(Project.Xml.Imports!=null){// search for this import statement and remove itvarimportElement=Project.Xml.Imports.FirstOrDefault(import=>targetPath.Equals(import.Project,StringComparison.OrdinalIgnoreCase));if(importElement!=null){Project.Xml.RemoveChild(importElement);NuGet.MSBuildProjectUtility.RemoveEnsureImportedTarget(Project,targetPath);Project.ReevaluateIfNecessary();Project.Save();}}}}}
I can't honestly remember if they do exactly the same thing, but they are pretty similar and implement the same interfaces and inheritance. As you can see, while F#'s focus is being functional it will support OO code just fine, which is very useful indeed when you need to interop with .NET code from other languages and coding styles.