我使用泛型有问题。我创建了一个名为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();
}
这是我创建一个名为ProblemA
的算术问题的示例。 T
是decimal
,因为数组数据类型应该是十进制的(其他问题可能有string
或int
)
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,所以我希望每个包含ProblemBase<T>
属性的问题都有一个ViewModel,但它是如何通用的,我猜它会是一个如果将IProblemViewModel
置于通用中,则会出现问题。
public interface IProblemViewModel : IViewModel
{
ProblemBase<T> Problem { get; set; }
}
我这样说是因为后来计划使用ObservableCollection<IProblemViewModel>
,所以如果我写IProblemViewModel
或IProblemViewModel<T>
,我不确定是否有问题。
提前谢谢。
答案 0 :(得分:2)
也许我没有完全理解这一点,但这就是你追求的目标吗?
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.
};
}
}
答案 1 :(得分:0)
您的视图模型界面可以这样定义:
public interface IProblemViewModel<T> : IViewModel
{
//No reason to use the base here instead of the interface
IProblem<T> Problem { get; set; }
}
我不确定您是否计划将问题绑定到WPF或Silverlight中的接口,但是如果您确定问题还实现 INotifyPropertyChanged 。在未实现INotifyPropertyChanged的对象上绑定到非依赖项属性会导致永远不会释放对象的内存泄漏。您可以在此处找到有关泄漏的更多信息:http://support.microsoft.com/kb/938416
编辑:添加了评论的答案。
如果您想要显示多种类型的IProblemViewModel<T>
,那么让<T>
阻止您在ObservableCollection中使用它是正确的。但是,当你绑定它时,绑定它时对象类型是什么并不重要,为什么不只是使集合成为ObservableCollection<IViewModel>
?