如何解析泛型类<;T>;脚本

本文关键字:gt 脚本 lt 何解析 泛型类 | 更新日期: 2023-09-27 18:20:06

我在使用泛型时遇到问题。我正在创建一个名为IProblem的接口,其中每个问题都有结果(答案)和结果(如果正确的话)

public interface IProblem<T>
{
    ushort ResultCount { get; }
    T[] Results { get; }
    bool IsCorrect();
}
public abstract class ProblemBase<T> : IProblem<T>
{
    private T[] _results;
    private ushort? _resultCount;
    public ushort ResultCount
    {
        get
        {
            if (_resultCount == null) throw new ArgumentNullException("_resultCount");
            return (ushort)_resultCount;
        }
        protected set
        {
            if (_resultCount != value)
                _resultCount = value;
        }
    }
    public T[] Results
    {
        get
        {
            if (_results == null)
                _results = new T[ResultCount];
            return _results;
        }
    }
    public abstract bool IsCorrect();
}

这是我创建一个算术问题的例子,称为ProblemATdecimal,因为数组数据类型应该是十进制的(其他问题可能有stringint

public class ProblemA: ProblemBase<decimal>
{
    private decimal _number1;
    private decimal _number2;
    private Operators _operator;
    public decimal Number1
    {
        get { return _number1; }
        set { _number1 = value; }
    }
    public decimal Number2
    {
        get { return _number2; }
        set { _number2 = value; }
    }
    public Operators Operator
    {
        get { return _operator; }
        set { _operator = value; }
    }
    public decimal Result
    {
        get { return Results[0]; }
        set { Results[0] = value; }
    }
    public ProblemA()
    {
        this.ResultCount = 1;
    }
    public override bool IsCorrect()
    {
        bool result;
        switch (_operator)
        {
            case Operators.Addition:
                result = this.Result == (this.Number1 + this.Number2);
                break;
            case Operators.Subtract:
                result = this.Result == (this.Number1 - this.Number2);
                break;
            case Operators.Multiplication:
                result = this.Result == (this.Number1 * this.Number2);
                break;
            case Operators.Division:
                result = this.Result == (this.Number1 / this.Number2);
                break;
            default:
                throw new ArgumentException("_operator");
        }
        return result;
    }
}

我使用的是MVVM,所以我希望每个问题都有一个ViewModel,其中包含ProblemBase<T>作为属性,但它如何是泛型,我想如果将IProblemViewModel作为泛型放入,那将是一个问题。

public interface IProblemViewModel : IViewModel
{
    ProblemBase<T> Problem { get; set; }
}

我这么说是因为后来计划使用ObservableCollection<IProblemViewModel>,所以我不确定如果我写IProblemViewModelIProblemViewModel<T>是否没有问题。提前谢谢。

如何解析泛型类<;T>;脚本

也许我还没有完全理解这一点,但这就是你想要的吗?

    ObservableCollection<IProblemViewModel<object>> collection = new ObservableCollection<IProblemViewModel<object>>
    {
        new ProblemViewModel<DerivedResult>(),
        new ProblemViewModel<OtherResult>()
    };

这可以通过将泛型参数声明为协变来实现。

您也可以将集合更改为

ObservableCollection<IProblem<BaseType>>

让它接受一个特定的结果链。在本例中,DerivedResult和OtherResult必须从BaseType继承才能适应集合。

最大的警告是,基元类型无论如何都不适合这种层次结构。你必须用IProblem<IntResult>包装它们,以此类推

当然,您可以实现一个简单的载体,例如Boxer,它将框住任何值类型,而不是为每个类型实现一个。

最后一个警告:协变类型上不可能有"set"属性,因此IProblemViewModel只能支持get

一个完整的、可编译的例子:

class Program
{
    public interface IProblem<out T>
    {
        ushort ResultCount { get; }
        T[] Results { get; }
        bool IsCorrect();
    }
    public class ProblemBase<T> : IProblem<T>
    {
        private T[] _results;
        private ushort? _resultCount;
        public ushort ResultCount
        {
            get
            {
                if (_resultCount == null) throw new ArgumentNullException("_resultCount");
                return (ushort)_resultCount;
            }
            protected set
            {
                if (_resultCount != value)
                    _resultCount = value;
            }
        }
        public T[] Results
        {
            get
            {
                if (_results == null)
                    _results = new T[ResultCount];
                return _results;
            }
        }
        public bool IsCorrect()
        {
            return true;
        }
    }
    public interface IProblemViewModel<out T>
    {
        IProblem<T> Problem { get; }
    }
    public class BaseResult
    {
    }
    public class DerivedResult : BaseResult
    {
    }
    public class OtherResult : BaseResult
    {
    }
    public class ProblemViewModel<T> : IProblemViewModel<T>
    {
        public IProblem<T> Problem
        {
            get
            {
                throw new NotImplementedException();
            }
            set
            {
                throw new NotImplementedException();
            }
        }
    }

    static void Main(string[] args)
    {
        ObservableCollection<IProblemViewModel<object>> collection = new ObservableCollection<IProblemViewModel<object>>
        {
            new ProblemViewModel<DerivedResult>(),
            new ProblemViewModel<OtherResult>()
            //, new ProblemViewModel<int>()   // This is not possible, does not compile.
        };
    }
}

您的视图模型接口可以这样定义:

public interface IProblemViewModel<T> : IViewModel
{
    //No reason to use the base here instead of the interface
    IProblem<T> Problem { get; set; }
}

我不确定您是否计划将Problem绑定到WPF或Silverlight中的接口,但如果您要确保Problem也实现了INotifyPropertyChanged。绑定到未实现INotifyPropertyChanged的对象的非依赖属性会导致内存泄漏,对象将永远不会被释放。你可以在这里找到更多关于泄漏的信息:http://support.microsoft.com/kb/938416

编辑:添加了评论的答案。

如果您打算显示多种类型的<T>,那么拥有IProblemViewModel<T>将阻止您在ObservableCollection中使用它,这是正确的。然而,既然在绑定时,绑定到对象时对象的类型并不重要,为什么不将集合设为ObservableCollection<IViewModel>呢?