首页 > 解决方案 > 检查变量是否是正确的类型及其 T if 指定的接口

问题描述

=== 已解决问题并将最佳解决方案添加到代码中 ===

你好我有以下问题。正如您在下面的代码中看到的,我有一个包含命令的命令堆栈。有不止一种类型的命令,每个命令类可以有不同的 T 参数,虽然这只能是继承 IModel 接口的类。

现在,当我想检查某种类型的命令当前是否在堆栈中时。我(直到我做错了)必须用模板指定整个类型,这非常不方便,因为它可能导致很长的 if-else 语句。

我想指定类类型,但我不关心它的模板类型。有没有办法做到这一点?

在您可以复制并运行的整个代码下方。它是完全可执行的,并且准确地显示了我想要实现的目标。

using System;
using System.Collections.Generic;

namespace ConsoleApp1
{
    public interface IModel { }
    class SomeDataModelA : IModel { }
    class SomeDataModelB : IModel { }
    // in reality there is more models and all of them implements IModel

    public interface IUndoRedoCommand 
    {
        void Undo();
        void Redo();
    }

    class RemoveCommand<IModel> : IUndoRedoCommand
    {
        public void Undo() => throw new NotImplementedException();
        public void Redo() => throw new NotImplementedException();
    }

    class AddCommand<IModel> : IUndoRedoCommand
    {
        public void Undo() => throw new NotImplementedException();
        public void Redo() => throw new NotImplementedException();
    }

    public class UndoRedoList<T> : List<T>
        where T : IModel
    {
        readonly CommandStack _commandStack;

        public UndoRedoList(CommandStack commandStack)
            : base()
        {
            _commandStack = commandStack;
        }

        public UndoRedoList(int capacity, CommandStack commandStack)
            : base(capacity)
        {
            _commandStack = commandStack;
        }

        public UndoRedoList(IEnumerable<T> enumerable, CommandStack commandStack)
            : base(enumerable)
        {
            _commandStack = commandStack;
        }

        public void AddWithUndoRedoTracking(T item)
        {
            Add(item);
            _commandStack.Push(new AddCommand<T>());
        }

        public void RemoveWithUndoRedoTracking(T item)
        {
            Remove(item);
            _commandStack.Push(new RemoveCommand<T>());
        }

        public void InsertWithUndoRedoTracking(int index, T item)
            => _commandStack.Push(new AddCommand<T>());
    }

    public class CommandStack
    {
        public int UndoCount => _pointer;
        public int RedoCount => _undoRedoStack.Count - _pointer;

        readonly IList<IUndoRedoCommand> _undoRedoStack = new List<IUndoRedoCommand>();
        int _pointer; // points at first redo - so first undo will be _pointer - 1

        public void Push(IUndoRedoCommand cmd) => _undoRedoStack.Insert(_pointer++, cmd);

        public void Refresh()
        {
            for (int i = 0; i < _undoRedoStack.Count; i++)
            {
                IUndoRedoCommand cmd = _undoRedoStack[i];
                if (cmd is AddCommand<IModel>)
                    Console.WriteLine("This doesn't work but it should.");

                if(cmd is AddCommand<SomeDataModelA>
                   || cmd is AddCommand<SomeDataModelB>
                   /* and so on for all models*/)
                    Console.WriteLine("This works but it is ugly.");

                // perfect solution by Sweeper
                if (cmd.GetType().GetGenericTypeDefinition() == typeof(AddCommand<>))
                    Console.WriteLine("This works too!! Thank you Sweeper.");
            }
        }
    }

    class Program
    {
        static void Main()
        {
            var stack = new CommandStack();
            var list = new UndoRedoList<SomeDataModelA>(stack);

            list.AddWithUndoRedoTracking(new SomeDataModelA());
            list.AddWithUndoRedoTracking(new SomeDataModelA());

            stack.Refresh();
        }
    }
}

标签: c#

解决方案


您可以使用GetType().GetGenericTypeDefinition(),并将类型与 进行比较==

if(cmd.GetType().GetGenericTypeDefinition() == typeof(AddCommand<>)) {

}

请注意,如果您希望 的子类AddCommand也输入if.


推荐阅读