Есть ли способ расширить встроенный тип для наследования интерфейса?
Я хочу добавить интерфейс к некоторым встроенным типам. У меня есть интерфейс IConcludable
, который я использую в качестве ограничения для Conclusion<T>
. Я не знаю, как подойти к этому, или если это даже возможно.
Основной макет
public interface IConcludable { }
public struct Conclusion<T> where T : IConcludable
{
public bool IsSuccessful;
public T Result;
// Constructors, members, etc.
}
public class ErrorReport : IConcludable { ... }
public class MathArg : IConcludable { ... }
public class ParseResult : IConcludable { ... }
Реализация
public Conclusion<ParseResult> ParseInput (string input)
{
// Parse input...
// Initialize ParseResult object...
return new Conclusion<ParseResult>(result);
}
Проблема
Когда я получаю окончательное значение, это встроенный тип типа int
, double
, string
, bool
и т.д. Я хотел бы использовать Conclusion<T>
как возврат, потому что у меня есть класс, который обрабатывает отчеты об ошибках, когда входная строка недействительна:
if (conclusion.ReturnObject is ErrorReport)
{
ErrorManager errorManager = new ErrorManager();
errorManager.Resolve(conclusion);
}
Исследование
Я искал ограничения.
Похоже, что ограничения только объединяются, поэтому включение интерфейсов каждого встроенного типа, который мне нужен, потребует определения горы методов, которые не имеют ничего общего с моей конструкцией Conclusion
.
Методы расширения
Это фактически изменяет поведение встроенных типов. Это не то, что я ищу, потому что мой интерфейс IConcludable
не имеет никаких методов.
Замена встроенных типов
Невозможно. Однако мне не нужно менять поведение этих типов. Я просто хочу добавить к нему пустой интерфейс.
Кажется, что нет никакого добавления интерфейса к встроенному типу. Я не уверен, что "Наследование" - это то, на что он будет ссылаться. Возможно ли это?
Edit
Лучшее объяснение выводов struct
Я использую вывод struct как возвращаемый объект в большинстве моих методов. Это потому, что я использую делегатов. См. Фактический код объектов ниже:
public delegate Conclusion<T> Validator<T>(T subclass) where T : IVerifiable<T>;
public delegate Conclusion<BaseFunction> Executor(BaseFunction subclass);
public struct Conclusion<T> where T : IConcludable
{
public bool IsSuccessful;
public T ReturnObject;
public Conclusion(T returnObject)
{
this.ReturnObject = returnObject;
this.IsSuccessful = returnObject is Error ? false : true;
}
}
public class BaseFunction : IVerifiable<BaseFunction>, IConcludable
{
public List<BaseArgument> Args;
public Executor Executing;
public Validator<BaseFunction> Validating;
public string UserInput;
public Conclusion<BaseFunction> Validate(BaseFunction subclass)
{
if (this.Validating != null)
{
return Validating(subclass);
}
else
{
StringBuilder message = new StringBuilder();
message.Append("A Validating delegate has not been assigned.");
throw new InvalidOperationException(message.ToString());
}
}
public Conclusion<BaseFunction> Execute(BaseFunction subclass)
{
if (this.Executing != null)
{
return this.Executing(subclass);
}
else
{
StringBuilder message = new StringBuilder();
message.Append("An Executing delegate has not been assigned.");
throw new InvalidOperationException(message.ToString());
}
}
}
public class Function<T> : BaseFunction
{
public T Result;
public Function()
{
base.Args = new List<BaseArgument>();
}
}
public class BaseArgument : IVerifiable<BaseArgument>, IConcludable
{
public string Role;
public string UserInput;
public int Position;
public Validator<BaseArgument> Validating;
public Conclusion<BaseArgument> Validate(BaseArgument subclass)
{
if (this.Validating != null)
{
return Validating(subclass);
}
else
throw new InvalidOperationException();
}
}
public class Argument<T> : BaseArgument
{
public T Value;
public Argument(int position)
{
base.Position = position;
}
}
public static class ExecutionHandler
{
public static Conclusion<BaseFunction> Sum(BaseFunction subclass)
{
subclass = (Function<double>)subclass;
// Execution code.
return new Conclusion<BaseFunction>(subclass);
}
public static Conclusion<BaseFunction> Concatenate(BaseFunction subclass)
{
subclass = (Function<double>)subclass;
// Execution code.
return new Conclusion<BaseFunction>(subclass);
}
}
Если мне нужно разместить больше, я сделаю это. но на самом деле это очень много. Тип возврата методов, назначенных всем делегатам, которые я использую, имеет тип возврата Conclusion<T>
, так что я могу иметь возвращаемый объект, а также ошибку, если это произойдет. Функции в приведенном выше коде возвращают Conclusion<BaseFunction>
, но этот возврат преобразуется в объект Addend<T>
, если он является числом. Если это часть другого типа функции, которая возвращает string
или bool
или другой тип, она преобразуется в другой тип класса. В конце числового вычисления возврат будет выглядеть как Conclusion<int>
или Conclusion<double>
. Поэтому добавление int
и double
в интерфейс IConcludable
- это то, что я пытаюсь сделать.
Лучшее объяснение приложения
Я пишу консольное приложение на С#. Он принимает данные от пользователя и записывает ответ. Ввод аналогичен формулам Excel: Sum(5, 15, Average(2, 3), 5)
или Concatenate("5 + 5 = ", Text(Sum(5, 5)))
. Строка ввода проверяется, анализируется и возвращает результат.
Ответы
Ответ 1
ОБНОВЛЕНО (ДОБАВИТЬ БОЛЬШЕ ОБЪЯСНЕНИЯ)
Как я уже сказал, я хочу объяснить немного больше о моем последнем ответе.
Требования
-
Conclusion
необходимо поддерживать как тип значения , так и ссылочный тип
- Generic
- Типы значений: все числовые типы данных (int, short, long и т.д.), boolean, char, date....
- Типы ссылок: строка и пользовательский класс (в образце OP,
IConcludable
)
Решение:
- Ввести базовый класс (
AbstractConclusion
), который принимает Object
как общий ввод
- Переместить логику в базовый класс для повторного использования
- Представьте две новые конкретные реализации, которые принимают
struct
и IConcluable
(есть возможность добавить больше реализации, для ex: string)
- Унаследованные классы могут использовать все методы базового класса
ОРИГИНАЛЬНЫЙ ОТВЕТ:
Вы можете поместить логику в класс AbstractConclusion
и иметь две ее реализации (Conclusion
, которая принимает IConcludeable
и PrimitiveConclusion
, которая принимает тип данных struct
)
Смотрите пример кода ниже:
void Main()
{
PrimitiveConclusion<int> primitiveConclusion = new PrimitiveConclusion<int>(1);
Conclusion<ParseResult> parseResultConclusion = new Conclusion<ParseResult>(new ParseResult {});
Console.WriteLine($"{primitiveConclusion.Result.GetType()}");
Console.WriteLine($"{parseResultConclusion.Result.GetType()}");
}
public class TestClass
{
public Conclusion<ParseResult> ParseInput(string input)
{
return new Conclusion<ParseResult>(null);
}
}
public interface IConcludable { }
public abstract class AbstractConclusion<T>
{
public AbstractConclusion(T t)
{
IsSuccessful = t != null;
Result = t;
}
public bool IsSuccessful;
public T Result;
}
public class Conclusion<T> : AbstractConclusion<T> where T : IConcludable
{
public Conclusion(T t) : base(t)
{
}
}
public class PrimitiveConclusion<T> : AbstractConclusion<T> where T : struct
{
public PrimitiveConclusion(T t) : base(t)
{
}
}
public class ParseResult : IConcludable { }
Ответ 2
С where T : IConcludable
общим ограничением типа вы не можете передать int
в качестве общего аргумента. А также нет способа добавить интерфейс к примитивному типу.
Вы можете сделать обходной путь, чтобы сделать это. Вы можете поместить основную логику Conclusion
в базовый абстрактный класс и наследовать от нее, реструктурировать Conclusion
как class
(потому что struct
не поддерживать наследование) и создавать классы
public class Conclusion<T> : BaseConclusion
where T : IConcludable
и
public class PrimitiveConclusion<T> : BaseConclusion
where T : struct
а также вы должны создать другой класс для string
, поскольку string
не является структурой и не реализует IConcludable
Как я знаю, нет другого способа передать разные типы в качестве общих аргументов.
Кроме того, вместо создания класса Conclusion
для встроенных типов вы можете создать структуру-оболочку, которая будет реализовывать IConcludable
. И иметь дело с ним
public struct Wrapper<T> : IConcludable
{
public T Value { get; set; }
}