我有一个表示不可变值的抽象类。与字符串一样,不可变类具有似乎更改实例的方法,但实际上只返回带有更改的新实例。抽象类具有一些具有某些默认行为的方法。我可以在抽象类中使用这种创建修改后的实例并返回逻辑吗?我被挂了,因为我不知道该把什么放在???位置。看起来我需要的是一个代表派生类型的类型T.有没有这样的模式来克服这个问题?
public abstract class BaseImmutable
{
public readonly object Value;
protected BaseImmutable(object val)
{
Value = val;
}
public ??? ModifiyButNotReally()
{
object newValue = GetNewObjectFromOld(Value);
return new ???(newValue);
}
}
public class DerivedImmutable : BaseImmutable
{
public DerivedImmutable(object val) : base(val)
{
}
}
ANSWER
这比我怀疑的要容易。可以使方法通用而不使类通用。考虑到这一点,我们唯一要做的就是将泛型参数限制为从基类继承,并通过包含new()约束来要求它不是抽象的。我需要做的最后一步是使用反射来获取非参数构造函数来创建新实例。我发现这个解决方案比@Jason提出的通用类答案更好,我从那时起就知道它被称为Curiously Recurring Template Pattern。它还避免了在@bottleneck建议的单独静态类中创建难以测试/ moq扩展方法的需要。然而,@ bottleneck的答案让我对解决方案有了灵感,所以积分给了他。
public abstract class BaseImmutable
{
public readonly object Value;
protected BaseImmutable(object val)
{
Value = val;
}
public T ModifiyButNotReally<T>() where T : BaseImmutable, new()
{
object newValue = GetNewObjectFromOld(Value);
var ctor = typeof(T).GetConstructor(new[] { typeof(object) });
return (T)ctor.Invoke(new object[] { newValue });
}
}
public class DerivedImmutable : BaseImmutable
{
public DerivedImmutable(object val) : base(val)
{
}
}
答案 0 :(得分:3)
你可以这样做:
abstract class BaseImmutable<T> {
// ...
public T ModifiedButNotReally() { // ... }
}
class DerivedImmutable : BaseImmutable<DerivedImmutable> { // ... }
我已经省略了大量的细节。
那就是说,这确实有点不好。基本上,我给你一个机制来解决你的问题,我不清楚,无论你建模什么,最好用你的设置建模。
答案 1 :(得分:3)
也许这里有extension method的顺序?
public static T Modify<T>(this T immutable) where T:BaseImmutable{
//work your magic here
//return T something
}
答案 2 :(得分:2)
杰森的方法可能是你拥有的最佳选择。您必须将运行时类型测试(unsafe cast)添加到目标类型,因为C#类型系统对此没有足够的表达能力,但它可以工作。
要添加一些背景 - 您要求的是自我类型。它能够在类型声明中引用当前实例的类型。这在某些语言中可用 - 对于example Scala,但不幸的是不在C#中。在带有自我类型的虚构C#中,您可以声明一个这样的虚拟方法:
public abstract class BaseImmutable {
public abstract self GetNewObjectFromOld();
}
实现该方法的类Foo
必须返回Foo
作为结果。要查找更多信息和解决方法,您可以尝试搜索在C#中模拟自我类型的各种方法。