首页 > 解决方案 > 在 C# 中为原始类型创建包装器的最佳方法是什么?

问题描述

我正在尝试制作一个使用终端/外壳与(几乎)一切交互的游戏(使用 Unity 3D 引擎)。这也是很多问题出现的地方,因为实现必须同时是刚性的、灵活的、简单的和可扩展的。

目前我对终端的美学并不感兴趣——只是 shell 的功能——因此我专注于创建一个命令类型,该类型可以从被解析为通用参数类型的字符串实例化然后转换为内部类型(如string,int等)。

下面,我提供了一个Command类的代码。我正在努力工作,但我一直试图将其解析为最终可以执行的一些动作。问题是班级ArgumentType内部Argument不想被强制转换,我没有找到任何好的解决方案。谁能帮我解决这个问题或给我一个工作方向?先感谢您!

namespace Terminal.Shells
{
    public abstract class Command
    {
        private readonly Action<ArgumentType []> procedure;
        private readonly CommandManual manual;

        public IEnumerable<Type> Parse (string line)
        {
            for (int i = 0; i < manual.RequiredArguments.Length; i++)
            {
                var word = EatNextWord (ref line);

                if (string.IsNullOrEmpty (word))
                    throw new System.Exception (); // TODO: index out of range

                var argumentType = manual.RequiredArguments [i].Type;

                // ### conversion from string to type
            }

            // TODO: Optional Arguments
        }

        public string EatNextWord (ref string line) { /* ... */ }
    }
}

该类CommandManual仅包含两个有趣的属性:

internal readonly Argument [] RequiredArguments;
internal readonly Argument [] OptionalArguments;

Argument班级:

namespace Terminal.Shells
{
    public struct Argument
    {
        private readonly string identifier;
        private readonly ArgumentType type;

        public string Identifier => this.identifier;
        public ArgumentType Type => this.type;

        // ...
    }
}

我创建了ArgumentTypeand ArgumentType<T>:第一个类似于一个Enumeration类,可以在任何地方使用,后者用于从输入(字符串)到关联类型的实际转换。

namespace Terminal.Shells
{
    public abstract partial class ArgumentType : Enumeration
    {
        public static readonly ArgumentType Command = new CommandType ();
        public static readonly ArgumentType Boolean = new BooleanType ();
        public static readonly ArgumentType String = new StringType ();
        public static readonly ArgumentType Range = new RangeType ();

        protected ArgumentType (string name, int value)
            : base (name, value) { }

        // ### THIS GOES WRONG
        public ArgumentType<T> GenericType => ???;
    }

    public abstract partial class ArgumentType<T> : ArgumentType
    {
        protected ArgumentType (string name, int value)
            : base (name, value) { }

        /// <summary>
        /// Tries to cast the value of an argument in this wrapper
        /// to an actual primitive value enclosed in a <see cref="Maybe{T}"/>.
        /// </summary>
        /// <returns>A <see cref="Maybe{T}"/> value that might contain the
        /// casted value.</returns>
        public abstract Maybe<T> TryCast (string input);

        /// <summary>
        /// Casts the value of an argument in this wrapper to
        /// an actual primitive value or throws an error.
        /// </summary>
        /// <returns>An <see cref="Either{T, ArgumentTypeException}"/> value
        /// that contains the casted value or an <see cref="ArgumentTypeException"/>.
        /// </returns>
        public virtual Either<T, ArgumentTypeException> Cast (string input)
        {
            return this
                .TryCast (input)
                .ValueOr (new ArgumentTypeException (
                    typeof (T),
                    typeof (void)
                ));
        }
    }
}

这种通用枚举类型的实例之一是IntegerType类:

namespace Terminal.Shells
{
    public class IntegerType : ArgumentType<int>
    {
        public IntegerType () : base ("integer", 4) { }

        /// <inheritdoc/>
        public override Maybe<int> TryCast (string input)
        {
            int.TryParse (input, out var result);
            return result;
        }
    }
}

标签: c#shellcastingcommand

解决方案


推荐阅读