Есть ли способ расширить встроенный тип для наследования интерфейса?

Я хочу добавить интерфейс к некоторым встроенным типам. У меня есть интерфейс 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; }
}