Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I want to add an interface to some built-in types. I have an interface, IConcludable, which I am using as a constraint for Conclusion<T>. I have no clue how to approach this, or if it is even possible.

Basic Layout

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 { ... }

Implementation

public Conclusion<ParseResult> ParseInput (string input)
{
    // Parse input...
    // Initialize ParseResult object...

    return new Conclusion<ParseResult>(result);
}

Problem

When I get the final value, it is a built-in type like int, double, string, bool, etc. I would like to use Conclusion<T> as a return because I have a class that handles error reports when the input string is invalid:

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

Research

I looked into constraints.

  • Is there a C# generic constraint for “real number” types? [duplicate]

It appears that constraints only add together, so including the interfaces of each built-in type that I need would require defining a mountain of methods that do not have anything to do with my Conclusion struct.


Extension methods

  • How to extend C# built-in types, like String?

These actually change the behavior of built-in types. It is not what I am looking for because my interface, IConcludable, does not have any methods.

Replacing built-in types

  • Overwrite built in .NET class

Not possible. I don't need to change the behavior of these types though. I just want to add an empty interface to it.

There does not seem to be anything regarding adding an interface to a built-in type. I'm not sure if "Inheritance" is what it would be referred to. Is this possible?

Edit

Better explanation of Conclusion struct

I am using the conclusion struct as a return object in most of my methods. This is because I am using delegates. See the actual code of the objects below:

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

If I need to post more, I will. but it's really a lot to look at. The return type of the methods assigned by all of the delegates I use have a return type of Conclusion<T> so that I can have a return object as well as an error if one occurs. The functions in the code above return Conclusion<BaseFunction>, but that return is converted into an object Addend<T> if it is a number. If it is a part of another type of function that returns a string or bool or other type, it is converted into a different type of class. By the end of a numeric calculation, the return will be something like Conclusion<int> or Conclusion<double>. So adding int and double to the IConcludable interface is what I am trying to do.

Better explanation of the application

I am writing a C# console application. It takes input from the user, and writes an answer. The input is similar to Excel formulas: Sum(5, 15, Average(2, 3), 5) or Concatenate("5 + 5 = ", Text(Sum(5, 5))). The input string is validated, parsed, and returns a result.

like image 937
Tyler Pantuso Avatar asked Dec 23 '15 07:12

Tyler Pantuso


People also ask

Can interface class be extended?

An interface can extend other interfaces, just as a class subclass or extend another class. However, whereas a class can extend only one other class, an interface can extend any number of interfaces.

How do you extend a class to an interface in Java?

An interface can extend another interface in the same way that a class can extend another class. The extends keyword is used to extend an interface, and the child interface inherits the methods of the parent interface.

Can we extend interface in TypeScript?

In TypeScript, interfaces can also extend classes, but only in a way that involves inheritance. When an interface extends a class, the interface includes all class members (public and private), but without the class' implementations.

Can an interface be inherited?

Interfaces can inherit from one or more interfaces. The derived interface inherits the members from its base interfaces. A class that implements a derived interface must implement all members in the derived interface, including all members of the derived interface's base interfaces.


1 Answers

UPDATED (ADD MORE EXPLANATION)

As requested, I want to explain a bit more about my last answer.

Requirements

  • The Conclusion need to support both value type and reference type
  • Generic
  • Value Types: all numeric data types (int, short, long, etc), boolean, char, date....
  • Reference Types: string and user-defined class (in OP's sample, IConcludable)

Solution:

  • Introduce a base class (AbstractConclusion) that accepts Object as generic input
  • Move the logic to base class for reuse
  • Introduce two new concrete implementations that accepts struct and IConcluable (have the ability to add more implementation, for ex: string)
  • The inherited classes are able to all the methods of base class

ORIGINAL ANSWER:

You can put the logic in AbstractConclusion class, and have two implementations of it (Conclusion which accepts IConcludeable and PrimitiveConclusion which accepts struct data type)

See code sample below:

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 { }
like image 80
Kien Chu Avatar answered Sep 29 '22 11:09

Kien Chu