Changes the declared type of a local, parameter, field, property or method return value, typically to a base type or interface its uses need ("use base type where possible"). Introduce Interface for Dependency uses it after Extract Interface.
Arguments
Argument Required Meaning toyes The new type, as it would be written in the declaring file: IWriter, IEnumerable<Order> parameterno With a method target, the parameter to change instead of the return type
Targets:
a field, property or method return type by symbol: "target": { "symbol": "F:Shop.Report._writer" }; a parameter by its method's symbol and parameter: "target": { "symbol": "M:Shop.Report.Print(Shop.FileWriter)" }, "arguments": { "parameter": "writer", "to": "IWriter" }; a local by a caret on its name: "target": { "file": "Report.cs", "caret": "marker" }.
Precondition
to names a type the declaring file can see, or can see once its namespace is imported.Everything still compiles: every value assigned or returned converts to the new type, and every use of the variable, or of the method's result, needs only what the new type offers. This covers callers in other files, overrides and interface implementations. Every use still reaches the same code: a call passing the variable picks the same overload, and a member used through the new type is the one used before, or one the old member overrides or implicitly implements.
The type is written in place. var is replaced by the new type. A nullable declaration stays nullable: FileWriter? becomes IWriter?. A variable declared alongside others gets a declaration of its own, after the original, with the new type. The declaring file gains a using directive when the new type needs one, and a qualified name its usings already cover is shortened.
Preserved
Behaviour: the checks above refuse any change that would make a use reach different code. Initializers, modifiers and comments of the declaration.
Limitations
The new type must be named; the most general type every use allows is not worked out. Uses through operators, conversions and pattern matching are left to the compile check, so a user-defined conversion that differs between the two types is not detected.
Error codes
Code Meaning type-not-foundto names no type the file can seeparameter-not-foundthe method has no parameter of that name incompatible-usecode using the variable or result would no longer compile changes-overloada use would reach a different overload or member
Cases
Expand all · Collapse all
Diffs show each file from before to after .
/*[*/ … /*]*/ marks a selection and /*^*/ a caret; the runner removes them before the refactoring runs.
# caller-needs-old-typeRefuses when a caller in another file needs the old return type
refusal
Target symbol M:Shop.Store.Pending
Refuses incompatible-use mentioning “Dispatch.cs”; every file is left unchanged
Dispatch.cs input
1 namespace Shop 2 { 3 public static class Dispatch 4 { 5 public static int Count (Store store) => store.Pending ().Count ; 6 } 7 }
Store.cs input
1 using System .Collections .Generic ;2 3 namespace Shop 4 { 5 public class Order 6 { 7 public bool Shipped ; 8 } 9 10 public class Store 11 { 12 private readonly List <Order > _orders = new List <Order >(); 13 14 public List <Order > Pending () => _orders.FindAll (o => !o.Shipped ); 15 } 16 }
View fixture on GitHub
# explicit-implementation-differsRefuses when a member used through the new type is implemented by a different member than the one called today
refusal
Target symbol F:Shop.Report._writer
Refuses changes-overload mentioning “Write”; every file is left unchanged
Report.cs input
1 namespace Shop 2 { 3 public class Report 4 { 5 // Where the report goes. 6 private readonly FileWriter _writer = new FileWriter (); 7 8 public void Print () => _writer.Write ("report" ); 9 } 10 }
Writers.cs input
1 namespace Shop 2 { 3 public interface IWriter 4 { 5 void Write (string text); 6 } 7 8 public class FileWriter : IWriter 9 { 10 public void Write (string text) 11 { 12 } 13 14 void IWriter .Write (string text) 15 { 16 } 17 } 18 }
View fixture on GitHub
# field-to-interfaceDeclares a field as the interface its uses need rather than the concrete class
success
Target symbol F:Shop.Report._writer
Report.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Report 4 4 { 5 5 // Where the report goes. 6 − private readonly FileWriter _writer = new FileWriter (); 6 + private readonly IWriter _writer = new FileWriter (); 7 7 8 8 public void Print () => _writer.Write ("report" ); 9 9 } 10 10 }
Writers.cs unchanged
1 1 namespace Shop 2 2 { 3 3 public interface IWriter 4 4 { 5 5 void Write (string text); 6 6 } 7 7 8 8 public class FileWriter : IWriter 9 9 { 10 10 public void Write (string text) 11 11 { 12 12 } 13 13 14 14 public void Flush () 15 15 { 16 16 } 17 17 } 18 18 }
View fixture on GitHub
# local-var-to-interfaceReplaces var with the interface for a local picked by the caret
success
Target Report.cs, the /*^*/ caret
Report.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Report 4 4 { 5 5 public void Print () 6 6 { 7 − var /*^*/ writer = new FileWriter (); 7 + IWriter writer = new FileWriter (); 8 8 writer.Write ("report" ); 9 9 } 10 10 } 11 11 }
Writers.cs unchanged
1 1 namespace Shop 2 2 { 3 3 public interface IWriter 4 4 { 5 5 void Write (string text); 6 6 } 7 7 8 8 public class FileWriter : IWriter 9 9 { 10 10 public void Write (string text) 11 11 { 12 12 } 13 13 14 14 public void Flush () 15 15 { 16 16 } 17 17 } 18 18 }
View fixture on GitHub
# member-not-on-new-typeRefuses when the variable is used for a member the new type does not have
refusal
Target symbol F:Shop.Report._writer
Refuses incompatible-use mentioning “Flush”; every file is left unchanged
Report.cs input
1 namespace Shop 2 { 3 public class Report 4 { 5 private readonly FileWriter _writer = new FileWriter (); 6 7 public void Print () 8 { 9 _writer.Write ("report" ); 10 _writer.Flush (); 11 } 12 } 13 }
Writers.cs input
1 namespace Shop 2 { 3 public interface IWriter 4 { 5 void Write (string text); 6 } 7 8 public class FileWriter : IWriter 9 { 10 public void Write (string text) 11 { 12 } 13 14 public void Flush () 15 { 16 } 17 } 18 }
View fixture on GitHub
# one-of-several-fieldsSplits a declaration of several fields and changes only the target
success
Target symbol F:Shop.Report._backup
Report.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Report 4 4 { 5 − private FileWriter _main = new FileWriter (), _backup = new FileWriter (); 5 + private FileWriter _main = new FileWriter (); 6 + private IWriter _backup = new FileWriter (); 6 7 7 8 public void Print () 8 9 { 9 10 _main.Write ("report" ); 10 11 _main.Flush (); 11 12 _backup.Write ("report" ); 12 13 } 13 14 } 14 15 }
Writers.cs unchanged
1 1 namespace Shop 2 2 { 3 3 public interface IWriter 4 4 { 5 5 void Write (string text); 6 6 } 7 7 8 8 public class FileWriter : IWriter 9 9 { 10 10 public void Write (string text) 11 11 { 12 12 } 13 13 14 14 public void Flush () 15 15 { 16 16 } 17 17 } 18 18 }
View fixture on GitHub
# overload-would-changeRefuses when a call passing the variable would pick a different overload
refusal
Target Report.cs, the /*^*/ caret
Refuses changes-overload mentioning “Describe”; every file is left unchanged
Report.cs input
1 namespace Shop 2 { 3 public class Report 4 { 5 public string Print () 6 { 7 var /*^*/ writer = new FileWriter (); 8 return Describe (writer); 9 } 10 11 private static string Describe (FileWriter writer) => "file" ; 12 13 private static string Describe (IWriter writer) => "any" ; 14 } 15 }
Writers.cs input
1 namespace Shop 2 { 3 public interface IWriter 4 { 5 void Write (string text); 6 } 7 8 public class FileWriter : IWriter 9 { 10 public void Write (string text) 11 { 12 } 13 14 public void Flush () 15 { 16 } 17 } 18 }
View fixture on GitHub
# parameter-not-foundRefuses a parameter name the method does not have
refusal
Target symbol M:Shop.Report.Print(Shop.FileWriter)
Arguments parameter"output"to"IWriter"
Refuses parameter-not-found mentioning “output”; every file is left unchanged
Report.cs input
1 namespace Shop 2 { 3 public class Report 4 { 5 public void Print (FileWriter writer) 6 { 7 writer.Write ("report" ); 8 } 9 } 10 }
Writers.cs input
1 namespace Shop 2 { 3 public interface IWriter 4 { 5 void Write (string text); 6 } 7 8 public class FileWriter : IWriter 9 { 10 public void Write (string text) 11 { 12 } 13 14 public void Flush () 15 { 16 } 17 } 18 }
View fixture on GitHub
# parameter-to-interfaceWidens a parameter to an interface, leaving callers in another file that pass the class
success
Target symbol M:Shop.Report.Print(Shop.FileWriter)
Arguments parameter"writer"to"IWriter"
Report.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Report 4 4 { 5 − public void Print (FileWriter writer) 5 + public void Print (IWriter writer) 6 6 { 7 7 writer.Write ("report" ); 8 8 } 9 9 } 10 10 }
Program.cs unchanged
1 1 namespace Shop 2 2 { 3 3 public static class Program 4 4 { 5 5 public static void Run () => new Report ().Print (new FileWriter ()); 6 6 } 7 7 }
Writers.cs unchanged
1 1 namespace Shop 2 2 { 3 3 public interface IWriter 4 4 { 5 5 void Write (string text); 6 6 } 7 7 8 8 public class FileWriter : IWriter 9 9 { 10 10 public void Write (string text) 11 11 { 12 12 } 13 13 14 14 public void Flush () 15 15 { 16 16 } 17 17 } 18 18 }
View fixture on GitHub
# property-keeps-nullableKeeps a property nullable when changing its type
success
Target symbol P:Shop.Report.Writer
Project nullable enable
Report.cs modified
1 1 namespace Shop 2 2 { 3 3 public class Report 4 4 { 5 − public FileWriter ? Writer { get ; set ; } 5 + public IWriter ? Writer { get ; set ; } 6 6 7 7 public void Print () => Writer ?.Write ("report" ); 8 8 } 9 9 }
Writers.cs unchanged
1 1 namespace Shop 2 2 { 3 3 public interface IWriter 4 4 { 5 5 void Write (string text); 6 6 } 7 7 8 8 public class FileWriter : IWriter 9 9 { 10 10 public void Write (string text) 11 11 { 12 12 } 13 13 14 14 public void Flush () 15 15 { 16 16 } 17 17 } 18 18 }
View fixture on GitHub
# return-type-to-baseReturns a more general type when every caller only enumerates the result
success
Target symbol M:Shop.Store.Pending
Store.cs modified
1 1 using System .Collections .Generic ;2 2 3 3 namespace Shop 4 4 { 5 5 public class Order 6 6 { 7 7 public bool Shipped ; 8 8 } 9 9 10 10 public class Store 11 11 { 12 12 private readonly List <Order > _orders = new List <Order >(); 13 13 14 − public List <Order > Pending () => _orders.FindAll (o => !o.Shipped ); 14 + public IEnumerable <Order > Pending () => _orders.FindAll (o => !o.Shipped ); 15 15 } 16 16 }
Dispatch.cs unchanged
1 1 namespace Shop 2 2 { 3 3 public static class Dispatch 4 4 { 5 5 public static void ShipAll (Store store) 6 6 { 7 7 foreach (var order in store.Pending ()) 8 8 order.Shipped = true ; 9 9 } 10 10 } 11 11 }
View fixture on GitHub
# type-from-another-namespaceImports the namespace of the new type
success
Target symbol F:Shop.Reports.Report._log
Report.cs modified
1 1 using System ;2 + using Shop .Logging ;2 3 3 4 namespace Shop .Reports 4 5 { 5 6 public class Report 6 7 { 7 − private readonly Logging .ConsoleLog _log = new Logging .ConsoleLog (); 8 + private readonly ILog _log = new Logging .ConsoleLog (); 8 9 9 10 public void Print () => _log.Info (DateTime .Now .ToString ()); 10 11 } 11 12 }
Logging/Log.cs unchanged
1 1 namespace Shop .Logging 2 2 { 3 3 public interface ILog 4 4 { 5 5 void Info (string message); 6 6 } 7 7 8 8 public class ConsoleLog : ILog 9 9 { 10 10 public void Info (string message) 11 11 { 12 12 } 13 13 } 14 14 }
Program.cs unchanged
1 1 namespace Shop 2 2 { 3 3 public static class Program 4 4 { 5 5 public static Reports .Report Create () => new Reports .Report (); 6 6 } 7 7 }
View fixture on GitHub
# type-not-foundRefuses a type that does not exist
refusal
Target symbol F:Shop.Report._writer
Refuses type-not-found mentioning “IPrinter”; every file is left unchanged
Report.cs input
1 namespace Shop 2 { 3 public class Report 4 { 5 // Where the report goes. 6 private readonly FileWriter _writer = new FileWriter (); 7 8 public void Print () => _writer.Write ("report" ); 9 } 10 }
Writers.cs input
1 namespace Shop 2 { 3 public interface IWriter 4 { 5 void Write (string text); 6 } 7 8 public class FileWriter : IWriter 9 { 10 public void Write (string text) 11 { 12 } 13 14 public void Flush () 15 { 16 } 17 } 18 }
View fixture on GitHub