Actually let's say I have some classes

public class Model { int id {get;set;} string Name {get;set;} override string ToString() { return id+";"+Name; } } public class LongModel { int id {get;set;} string Name {get;set;} bool active {get;set;} override string ToString() { return id+";"+Name+";"+active; } } 

Now I have a class to convert

 public static class ModelConverter { public static Model ToModel(this LongModel LM) { return new Model{id=LM.id, Name =LM.Name}; } // ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠ· строки самой ΠΌΠΎΠ΄Π΅Π»ΠΈ, ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠ· строки Π΄Π»ΠΈΠ½Π½ΠΎΠΉ ΠΌΠΎΠ΄Π΅Π»ΠΈ ΠΈ ΠΏΡ€. } 

Is it possible to do something so that these methods can be called as Convert.ToModel(longModel) without having to prescribe the full path for each case:

  System.Convert.Toint32(...); Myproject.Convert.ToModel(longModel); 

Is it even possible to achieve this? NB The full way is to prescribe because of the name conflict, in fact, the question is asked to avoid the name conflict, but always use the same name Convert.

  • one
    if functions are now organized as extensions, why not use them as extensions: longModel.ToModel() , why should we try to add them to Convert ? - Grundy
  • @Grundy because there is still getting a string, and converting it back. - Monomax
  • one
    From the point of view of code organization and operations on business objects, simple type conversion and model conversion are different types of responsibilities, so the result that you want to get at least violates SRP - tym32167
  • one
    In terms of code flexibility, static classes cannot be replaced by other implementations in runtime, which makes the code less flexible. Moreover, a client of this class must have a link to the assembly where this class is located. And in addition, the client cannot declare a dependency on a similar class in the constructor, which is essentially contrary to DI - tym32167
  • one
    Well, in the follow-up, based on what I wrote above, the use of a static class by the client, which contains business logic, greatly complicates unit testing, since it is impossible to replace static method calls with alternative implementations (for example, a stub) - tym32167

2 answers 2

You cannot add methods to the already existing class Convert , it is not designed for possible extensions. But you can include its functionality in your class. To do this, we will add all methods from System.Convert to Myproject.Convert !

Of course, doing it manually is wrong, we will come to the aid of code generation. Let's write the auxiliary project:

 using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; // ... static string Stringify(Type t) => t.FullName; static string Stringify(IEnumerable<Type> tl) => string.Join(", ", tl.Select(Stringify)); static string Stringify(ParameterInfo pi) { if (pi.IsIn || pi.ParameterType.IsByRef || pi.HasDefaultValue) throw new NotSupportedException(); return $"{Stringify(pi.ParameterType)} {pi.Name}"; } static string Stringify(IEnumerable<ParameterInfo> pl) => string.Join(", ", pl.Select(Stringify)); static string StringifyNames(IEnumerable<ParameterInfo> pl) => string.Join(", ", pl.Select(p => p.Name)); static void Main(string[] args) { var methods = typeof(Convert) .GetMethods(BindingFlags.Public | BindingFlags.Static); using (var outf = File.CreateText("Convert.proxy.cs")) { outf.WriteLine("using System.Runtime.CompilerServices;"); outf.WriteLine(); outf.WriteLine("namespace MyProject"); outf.WriteLine("{"); outf.WriteLine(" static partial class Convert"); outf.WriteLine(" {"); outf.WriteLine(); foreach (var method in methods) { outf.WriteLine(" [MethodImpl(MethodImplOptions.AggressiveInlining)]"); outf.Write($" public static {method.ReturnType.FullName} {method.Name}"); if (method.IsGenericMethodDefinition) outf.Write($"<{Stringify(method.GetGenericArguments())}>"); var parameters = method.GetParameters(); outf.WriteLine($"({Stringify(parameters)}) => " + $"System.Convert.{method.Name}({StringifyNames(parameters)});"); outf.WriteLine(); } outf.WriteLine(" }"); outf.WriteLine("}"); } } 

This code will generate a file called Convert.proxy.cs , which you connect to the main project:

 using System.Runtime.CompilerServices; namespace MyProject { static partial class Convert { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static System.TypeCode GetTypeCode(System.Object value) => System.Convert.GetTypeCode(value); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static System.Boolean IsDBNull(System.Object value) => System.Convert.IsDBNull(value); 

and. etc.

Since the class is declared as partial , you can add functions to it without editing the generated text. For example, in addition in another file you can write:

 namespace MyProject { static partial class Convert // добавляСм ΠΌΠ΅Ρ‚ΠΎΠ΄Ρ‹ Π² класс Convert { public static Model ToModel(LongModel LM) { return new Model { id = LM.id, Name = LM.Name }; } } // ΠΈ Ρ‚. Π΄. } 

Everything, now everywhere you can use MyProject.Convert .

  • like that hard :) - tym32167
  • @ tym32167: But cheap, reliable and practical ( v ) - VladD
  • cheap - I agree, but reliability and practicality raises questions) - tym32167
  • @ tym32167: To make it safer, you need to connect via T4 in case, if suddenly in the new version of the framework Convert proapdateyt. And what is the impracticality? Too much fuss? Well, yes, the author of the question wants a strange, but a strange one can be achieved only by strange methods. - VladD
  • one
    Well, impracticality is more about the task itself, and not about the way you decided it. It seems to me doubtful to confuse the logic of converting simple data types with converting models - this is somehow not SOLID'no - tym32167

You cannot extend static classes.

However, in your case, it may be more convenient to use cast operators? For example, I have two classes of points - the first one stores x and y in int, and the second one in byte. In any of these classes, you can declare casting operators to another class. It will look like this:

 public static implicit operator Point2Int(Point2Byte bytePoint) { return new Point2Int(bytePoint.X, bytePoint.Y); } public static explicit operator Point2Byte(Point2Int bytePoint) { return new Point2Byte((byte)bytePoint.X, (byte)bytePoint.Y); } 

implicit - says that this cast will be done "silently", i.e. it is not necessary to implement it explicitly, but explicit , that it will require an explicit indication of the need for a cast.

Here is an example of use:

 //создали Π½ΠΎΠ²Ρ‹ΠΉ Point2Int var pointInt = new Point2Int(1, 1); //Ρ‚.ΠΊ. ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ ΠΊ Point2Byte explicit - трСбуСтся ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠ΅ явно Point2Byte pointByte = (Point2Byte)pointInt; //ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ΅ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ implicit - поэтому Π½ΠΈΡ‡Π΅Π³ΠΎ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ pointInt = pointByte; 

explicit should be used where data loss is possible (in my example, int is more than a byte and values ​​may be lost when casting, if X, for example, is 400).
implicit can be used if the loss is impossible (in my case, byte will quietly turn into int)

  • Statically, the class is given as an example of what I want to get, in fact, the problem is that I convert the extended model, or line 9 if it is in the correct format in the narrow model, maybe vice versa, but I also need to create the ModelConverter class, although I really want I’ll just call it Converter , but if I do it, then I need to explicitly indicate which converter I want to get, which I don’t want to do. - Monomax
  • @Monomax, I showed you an example of how to do this without the Convert class in general), but according to the comment, I am a bit confused about what you want to get - M. Green