Собственно допустим у меня есть некоторые классы
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;
}
}
Сейчас у меня есть класс для конвертирования
public static class ModelConverter
{
public static Model ToModel(this LongModel LM)
{
return new Model{id=LM.id, Name =LM.Name};
}
// конвертирование из строки самой модели, конвертирование из строки длинной модели и пр.
}
Можно ли как-то сделать так что-бы эти методы можно было вызывать как Convert.ToModel(longModel)
при этом что-бы не пришлось прописывать для каждого случая полный путь:
System.Convert.Toint32(...);
Myproject.Convert.ToModel(longModel);
Можно ли вообще такого добиться? N.B. Полный путь приходиться прописывать из-за конфликта имен, по сути вопрос, задан с целю избежать конфликта имен, но использовать всегда одно наименование Convert.
Вы не сможете добавить методы в уже существующий класс Convert
, он не спроектирован с учётом возможного расширения. Но можно включить его функциональность в ваш класс. Для этого внесём в Myproject.Convert
все методы из System.Convert
!
Разумеется, делать это вручную неправильно, нам на помощь придёт кодогенерация. Напишем вспомогательный проект:
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("}");
}
}
Этот код сгенерирует файл Convert.proxy.cs
, который вы подключите к основному проекту:
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);
и. т. д.
Поскольку класс объявлен как partial
, в него можно добавлять функции, не редактируя сгенерированный текст. Например, дополнительно в другом файле можно написать:
namespace MyProject
{
static partial class Convert // добавляем методы в класс Convert
{
public static Model ToModel(LongModel LM)
{
return new Model { id = LM.id, Name = LM.Name };
}
}
// и т. д.
}
Всё, теперь везде можно использовать MyProject.Convert
.
Расширять статические классы нельзя.
Однако, в вашем случае, возможно, удобнее будет использовать операторы приведения? Например, у меня есть два класса точек - первый хранит x и y в int, а второй в byte. В любом из этих классов можно объявить операторы приведения к другому классу. Выглядеть это будет так:
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
- говорит, что это приведение будет осуществляться "тихо", т.е. не нужно осуществлять его явно, а explicit
, что для него потребуется явное указание необходимости приведения.
Вот пример использования:
//создали новый Point2Int
var pointInt = new Point2Int(1, 1);
//т.к. приведение к Point2Byte explicit - требуется указать преобразование явно
Point2Byte pointByte = (Point2Byte)pointInt;
//обратное приведение implicit - поэтому ничего указывать не нужно
pointInt = pointByte;
explicit
стоит использовать там, где возможна потеря данных (в моём примере int больше байта и при приведении могут потеряться значения, если X, например будет равен 400).
implicit
можно использовать, если потеря невозможна (в моём случае byte спокойно превратится в int)
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
В окне WPF имеется множество контролов разных типов в перемешкуКонкретнее: анкета из 25 вопросов, в каждом из которых 10-12 вариантов, отраженных...
Есть стандартный код: