【问题标题】:Is there a way to extend a built-in type to inherit an interface?有没有办法扩展内置类型来继承接口?
【发布时间】:2015-12-23 07:54:59
【问题描述】:

我想为一些内置类型添加一个接口。我有一个接口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&lt;T&gt; 作为返回,因为我有当输入字符串无效时处理错误报告的类:

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

研究

我研究了约束

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


扩展方法

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

替换内置类型

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

似乎没有任何关于向内置类型添加接口的内容。我不确定是否会提到“继承”。这可能吗?

编辑

对结论结构的更好解释

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

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&lt;T&gt;,这样我就可以有一个返回对象以及一个错误如果发生。上面代码中的函数返回Conclusion&lt;BaseFunction&gt;,但是如果它是一个数字,则该返回被转换为一个对象Addend&lt;T&gt;。如果它是返回stringbool 或其他类型的其他类型函数的一部分,则将其转换为不同类型的类。在数值计算结束时,返回类似于Conclusion&lt;int&gt;Conclusion&lt;double&gt;。所以将intdouble添加到IConcludable接口就是我想做的。

更好地解释应用程序

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

【问题讨论】:

  • 正如我在您的实现中看到的,您正在返回结论。但是你也说我得到最终值的时候,是int、double、string、bool等内置类型,这部分我没看懂.
  • 虽然你的问题说得很好,但我认为你应该加强 actual question 你有,因为目前尚不清楚什么不适用于这个结构。
  • 这不是适配器模式的场景吗?
  • @kienct89 :我将发布对问题的编辑以更好地解释它。谢谢。
  • @LeiYang :我不确定适配器模式是什么。我对编程还是有点陌生​​。这是一个 C# 控制台应用程序,它读取输入行,并对其进行解析以产生结果,并将其显示给用户。

标签: c# inheritance built-in


【解决方案1】:

更新(添加更多解释)

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

要求

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

解决方案:

  • 引入一个接受 Object 作为通用输入的基类 (AbstractConclusion)
  • 将逻辑移至基类以供重用
  • 引入两个新的具体实现,接受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。这就是您的示例中抽象类的用途吗?谢谢。
  • @TylerPantuso: AbstractConclusion 只是一个基类,用于对所有结论的类似功能进行分组,因此您无需为所有子类重写。对于您问题的第二部分,它应该接受所有类型(以支持原始、int 和 IConcluable)。
  • IConcludable 不需要完全删除吗?
  • @TylerPantuso:Conclusion 类仍在使用 IConcluable,只有 AbstractConclusion 未使用。
  • 很好的解决方案!我建议进行修改以解释您的工作。它是为主要问题提供一般性答案。到时候我会接受的。谢谢!
【解决方案2】:

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

您可以采取一些解决方法来做到这一点。你可以把Conclusion的主要逻辑放到基础抽象类中继承,把Conclusion重构为class(因为structs不支持继承)并创建类

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

【讨论】:

    猜你喜欢
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    • 2013-10-04
    • 2011-12-15
    • 2014-09-07
    • 1970-01-01
    相关资源
    最近更新 更多