有没有办法扩展内置类型以继承接口?

Is there a way to extend a built-in type to inherit an interface?

我想为某些内置类型添加接口。我有一个接口 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);
}

问题

当我得到最终值时,它是一个内置类型,如intdoublestringbool等,我想使用 Conclusion<T> 作为 return 因为我有一个 class 在输入字符串无效时处理错误报告:

if (conclusion.ReturnObject is ErrorReport)
{
    ErrorManager errorManager = new ErrorManager();
    errorManager.Resolve(conclusion);
}

研究

我调查了约束

似乎约束只是相加,因此包括我需要的每个内置类型的接口将需要定义一大堆与我的 Conclusion 结构无关的方法。


扩展方法

这些实际上改变了内置类型的行为。这不是我要找的,因为我的界面 IConcludable 没有任何方法。

替换内置类型

不可能。不过,我不需要更改这些类型的行为。我只想给它添加一个空接口。

似乎没有关于向内置类型添加接口的任何内容。我不确定 "Inheritance" 是否是它所指的。这可能吗?

编辑

结论结构的更好解释

我在大多数方法中都将结论结构用作 return 对象。这是因为我正在使用委托。请参阅以下对象的实际代码:

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);
    }
}

如果我需要 post 更多,我会的。但确实有很多值得一看的地方。我使用的所有委托分配的方法的 return 类型有一个 return 类型的 Conclusion<T> 这样我就可以有一个 return 对象以及一个错误如果一个发生。上面代码中的函数return Conclusion<BaseFunction>,但是那个return如果是数字的话会转成一个对象Addend<T>。如果它是 return 为 stringbool 或其他类型的另一种类型函数的一部分,则将其转换为不同类型的 class。在数值计算结束时,return 将类似于 Conclusion<int>Conclusion<double>。因此,将 intdouble 添加到 IConcludable 界面就是我想要做的。

更好地解释应用程序

我正在编写 C# 控制台应用程序。它接受用户的输入,并写下答案。输入类似于 Excel 公式:Sum(5, 15, Average(2, 3), 5)Concatenate("5 + 5 = ", Text(Sum(5, 5)))。输入字符串经过验证、解析,并且 return 得到结果。

使用 where T : IConcludable 泛型类型约束,您不能将 int 作为泛型参数传递。而且也没有办法将接口附加到原始类型。

您可以采取一些解决方法来执行此操作。可以把Conclusion的主要逻辑放到base abstract class中继承,将Conclusion重构为class(因为struct不支持继承),创建 classes

public class Conclusion<T> : BaseConclusion
where T : IConcludable

public class PrimitiveConclusion<T> : BaseConclusion
where T : struct

并且您还应该为 string 创建另一个 class,因为 string 不是结构并且没有实现 IConcludable

据我所知,没有其他方法可以将不同类型作为泛型参数传递。


此外,您可以创建包装器结构,而不是为内置类型创建 Conclusion class,它将实现 IConcludable。并与之达成协议

public struct Wrapper<T> : IConcludable
{
    public T Value { get; set; }
}

已更新(添加更多说明)

根据要求,我想对我的上一个回答做更多的解释。

要求

  • Conclusion需要同时支持值类型和引用类型
  • 通用
  • 值类型:所有数字数据类型(int、short、long 等)、boolean、char、date....
  • 引用类型:字符串和用户定义的class(在OP的示例中,IConcludable

解法:

  • 引入接受 Object 作为通用输入的基 class (AbstractConclusion)
  • 将逻辑移至基础 class 以供重用
  • 引入两个接受structIConcluable的新具体实现(能够添加更多实现,例如:字符串)
  • 被继承的classes可以使用baseclass
  • 的所有方法

原始答案:

您可以将逻辑放在 AbstractConclusion class 中,并有两个实现(Conclusion 接受 IConcludeablePrimitiveConclusion 接受 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 { }