有没有一种方法可以扩展内置类型以继承接口?

10
我希望为一些内置类型添加接口。我有一个名为 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>作为返回值,因为我有一个处理输入字符串无效时的错误报告的类:

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

研究

我研究了约束

看起来约束只是简单地添加在一起,因此包括我需要的每个内置类型的接口将需要定义大量与我的Conclusion结构没有任何关系的方法。


扩展方法

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

替换内置类型

不可能。但我并不需要更改这些类型的行为。我只想向其中添加一个空接口。

似乎没有关于向内置类型添加接口的内容。我不确定是否应该称之为“继承”。这可能吗?

编辑

更好的解释Conclusion结构

我在大多数方法中使用Conclusion结构作为返回对象。这是因为我正在使用委托。请参阅下面对象的实际代码:

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>。因此,我正在尝试将intdouble添加到IConcludable接口中。
更好的应用程序解释:
我正在编写一个C#控制台应用程序。它从用户处获取输入,并输出答案。输入类似于Excel公式:Sum(5, 15, Average(2, 3), 5)Concatenate("5 + 5 = ", Text(Sum(5, 5)))。输入字符串经过验证、解析并返回结果。

根据您的实现,我看到您正在返回Conclusion<T>。但是您还说:“当我获得最终值时,它是一种内置类型,如int、double、string、bool等”,我不理解这部分。 - Kien Chu
虽然你的问题表述得非常好,但我认为你应该明确你所提出的实际问题,因为目前还不清楚这个结构有什么问题。 - Yuval Itzchakov
1
这不是“适配器模式”的场景吗? - Lei Yang
@kienct89:我会编辑问题并更好地解释它。谢谢。 - Tyler Pantuso
@LeiYang:我不确定适配器模式是什么.. 我还是编程新手。这是一个C#控制台应用程序,它读取输入行,并解析它以产生结果,并将其显示回用户。 - Tyler Pantuso
2个回答

1

更新(添加更多解释)

根据要求,我想再解释一下我的上一个答案。

要求

  • 结论需要支持值类型和引用类型
  • 泛型
  • 值类型:所有数字数据类型(int、short、long等)、布尔值、字符、日期……
  • 引用类型:字符串和用户定义的类(在OP的示例中,IConcludable

解决方案:

  • 引入一个基类(AbstractConclusion),它接受Object作为通用输入
  • 将逻辑移动到基类以便重用
  • 引入两个新的具体实现,接受structIConcluable(可以添加更多实现,例如:字符串)
  • 继承类能够使用基类的所有方法

原始答案:

你可以将逻辑放在AbstractConclusion类中,并有两个实现(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 { }

kienct89,我正在尝试理解抽象类的作用。它似乎可以接受任何值。就像T等同于object一样。这是你示例中抽象类的作用吗?谢谢。 - Tyler Pantuso
@TylerPantuso:AbstractConclusion只是一个基类,用于将所有Conclusion的相似功能分组,这样您就不需要为所有子类重写。对于您问题的第二部分,它应该接受所有类型(以支持原始类型、int和IConcluable)。 - Kien Chu
IConcludable” 需要完全删除吗? - Tyler Pantuso
@TylerPantuso:Conclusion类仍在使用IConcluable接口,只有AbstractConclusion没有使用。 - Kien Chu
很棒的解决方案!我建议一个编辑,重新表述了您的工作。它是为了提供一个对主要问题的普遍回答。我会接受它的。谢谢! - Tyler Pantuso

0

使用 where T : IConcludable 泛型类型约束,你无法将 int 作为泛型参数传递。而且也没有办法将一个接口添加到基本类型中。

你可以用一些变通方法来解决这个问题。你可以将 Conclusion 的主要逻辑放在一个基础抽象类中,并从该类继承,将 Conclusion 重构为 class (因为 struct 不支持继承),并创建类。

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

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

并且你应该为字符串创建另一个类,因为字符串既不是结构体也没有实现IConcludable

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


此外,您可以创建包装结构体来实现 IConcludable,而不是为内置类型创建 Conclusion 类。然后与其进行交互。
public struct Wrapper<T> : IConcludable
{
    public T Value { get; set; }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接