我正在使用Range<T>
class described in this answer。
我创建了以下子类,以创建特定类型的范围:
if(isset($_POST['my_data'])){
//process form
}
为了完成public class IntRange : Range<Int32>
{
public static List<IntRange> ParseRanges(string ranges)
{
//...
}
}
功能,我需要从ParseRanges
投射到Range<Int32>
。这是因为我正在调用我添加到IntRange
类的辅助函数:
Range<T>
方法调用如下所示:
//Create a range that automatically determines the min/max between two bounds.
public static Range<T> Create(T bound1, T bound2)
{
if (bound1.CompareTo(bound2) <= 0)
{
return new Range<T>() { Minimum = bound1, Maximum = bound2 };
}
else
{
return new Range<T>() { Minimum = bound2, Maximum = bound2 };
}
}
首先,我知道我不能合法地进行演员表演,因为另一个人可以创建一个班级:
IntRange range = (IntRange)Create(2, 0);
编译器不可能知道public class VerySpecialIntRange : Range<Int32> { /* ... */ }
应该是Range<Int32>
还是IntRange
,因此当我尝试强制转换时它会出错。
如何进行此转换,以便我不需要为每个子类推出VerySpecialIntRange
函数?当然,我有自己的源代码,可以相对容易地做到这一点,但如果Create
是某个封闭的第三方库的一部分,我需要将其子类化,我不能轻易确定如何正确实现Range<T>
函数。
答案 0 :(得分:0)
您需要更改创建方法以创建正确的范围:
public class IntRange : Range<Int32>
{
public static List<IntRange> ParseRanges(string ranges)
{
return new[] { Create<IntRange, int>(1, 2) }.ToList();
}
}
public static TRangeType Create<TRangeType, TItemType>(TItemType bound1, TItemType bound2)
where TRangeType : Range<TItemType>, new()
where TItemType : IComparable<TItemType>
{
if (bound1.CompareTo(bound2) <= 0)
{
return new TRangeType { Minimum = bound1 };
}
else
{
return new TRangeType { Minimum = bound2, Maximum=bound2 };
}
}
答案 1 :(得分:0)
使用构造函数而不是静态方法,这也允许您使Minimum
和Maximum
属性的setter保护/私有,因为它们确实应该是(如果用户能够更改)它们的值,最终在实例化后重新定义对象?)。当默认逻辑足够时,将参数传递给基础构造函数,如果要覆盖派生类中的逻辑,请使用默认的base()
构造函数。
public class Range<T>
{
Range() { }
Range( T bound1, T bound2 ) { /* your static method logic here */ }
}
public class IntRange : Range<int>
{
IntRange( int bound1, int bound2 )
: base( bound1, bound2 )
{ }
IntRange( int b1, int b2, bool someExampleFlag )
{
// custom logic here
}
}
答案 2 :(得分:0)
这样做有点棘手,但你基本上需要创建一个抽象的工厂模式。
首先,我会将原来的Range<T>
类更改为签名public class Range<T> : Range where T : IComparable<T>
。
现在我将Range
类定义为:
public class Range
{
private static Dictionary<Type, Delegate> _factories = new Dictionary<Type, Delegate>();
public static void AddFactory<T>(Func<T, T, Range<T>> factory) where T : IComparable<T>
{
_factories.Add(typeof(T), factory);
}
public static Range<T> Create<T>(T bound1, T bound2) where T : IComparable<T>
{
Func<T, T, Range<T>> factory =
_factories.ContainsKey(typeof(T))
? (Func<T, T, Range<T>>)_factories[typeof(T)]
: (Func<T, T, Range<T>>)((n, x) => new Range<T>()
{
Minimum = bound1,
Maximum = bound2
});
return
bound1.CompareTo(bound2) <= 0
? factory(bound1, bound2)
: factory(bound2, bound1);
}
}
这样做会创建一个Dictionary<Type, Delegate>
,它可以容纳您需要创建所有要定义的特殊范围类型的不同工厂。当您致电Create<T>
时,T
的类型用于检查您是否有特殊工厂,如果您这样做,它会使用此工厂来创建您的范围,否则它将使用默认值{{} 1}} class。
要使这项工作成为必需的非通用Range<T>
课程。如果您尝试将工厂代码放在Range
中,则每Range<T>
个单独的_factories
个实例。使用非泛型类,您只能得到一个。
您可以像这样定义工厂:
T
现在您可以像这样调用您的创建代码:
Range.AddFactory<int>((n, x) => new IntRange() { Minimum = n, Maximum = x });
这样运行并完美无缺。