gpt4 book ai didi

C# 不可变类子类

转载 作者:太空宇宙 更新时间:2023-11-03 10:34:37 25 4
gpt4 key购买 nike

我有一个不可变类型,我想创建它的一个子类,它可以访问所有相同的方法。

但是,由于必须如何实现不可变类,基类方法返回我的父类型,而不是我的子类型。是否可以创建一个不可变类,该类可以具有返回子类的子类?

下面是在 LinqPad 中运行的示例代码,用于演示问题

void Main()
{
var immutable = new MyImmutable(new Dictionary<ImmutableKey, decimal>{
{ ImmutableKey.Key1, 1 },
{ ImmutableKey.Key2, -5 },
{ ImmutableKey.Key3, 1.25m },
});

var immutable2 = new MyImmutable(new Dictionary<ImmutableKey, decimal>{
{ ImmutableKey.Key1, 1 },
{ ImmutableKey.Key2, 2 },
{ ImmutableKey.Key3, 3 },
});

var added = immutable.Apply((a, b) => a + b, immutable2);
added[ImmutableKey.Key1].Dump();
added[ImmutableKey.Key2].Dump();
added[ImmutableKey.Key3].Dump();

var subImmutable1 = new SubImmutable(1, new Dictionary<ImmutableKey, decimal>{
{ ImmutableKey.Key1, 1 },
{ ImmutableKey.Key2, -5 },
{ ImmutableKey.Key3, 1.25m },
});
var subImmutable2 = new SubImmutable(1, new Dictionary<ImmutableKey, decimal>{
{ ImmutableKey.Key1, 1 },
{ ImmutableKey.Key2, 2 },
{ ImmutableKey.Key3, 3 },
});

var subImmutableAdded = subImmutable1.Apply((a, b) => a + b, subImmutable2);
subImmutableAdded.GetType().Name.Dump(); //prints MyImmutable, it's not a SubImmutable
//after adding two SubImmutables, the type is changed back to the base type

var asSub = (SubImmutable)subImmutableAdded; // Unable to cast object of type 'MyImmutable' to type 'SubImmutable', SomeOtherValue was lost.
}

public enum ImmutableKey
{
Key1,
Key2,
Key3
}

public class MyImmutable
{
protected static readonly IEnumerable<ImmutableKey> AllKeys = Enum.GetValues(typeof(ImmutableKey)).Cast<ImmutableKey>();

private Dictionary<ImmutableKey, decimal> _dict { get; set; }

public MyImmutable(Dictionary<ImmutableKey,decimal> d)
{
_dict = d;
}

public decimal this[ImmutableKey key]
{
get
{
if (_dict == null || !_dict.ContainsKey(key))
return 0;

return _dict[key];
}
}

public MyImmutable Apply(Func<decimal, decimal, decimal> aggFunc, MyImmutable y)
{
var aggregated = new Dictionary<ImmutableKey, decimal>(AllKeys.Count());
foreach (ImmutableKey bt in AllKeys)
{
aggregated[bt] = aggFunc(this[bt], y[bt]);
}
return new MyImmutable(aggregated);
}
}

public class SubImmutable : MyImmutable
{
public int SomeOtherValue { get; set; }
public SubImmutable(int someValue, Dictionary<ImmutableKey,decimal> d)
:base(d)
{
SomeOtherValue= someValue;
}
}

输出:

2

-3

4.25

MyImmutable

InvalidCastException: Unable to cast object of type 'MyImmutable' to type 'SubImmutable'.

有没有一种方法可以让我拥有一个继承的不可变类型,它可以继承基类型中的所有方法,而不必全部重新实现它们?

配套代码审查问题:https://codereview.stackexchange.com/questions/79380/inheriting-methods-of-an-immutable-type

最佳答案

您可以使用虚拟方法来获取新实例。

在基类中创建一个虚方法,该方法接受输入以创建基类的新实例并返回基类的新实例。然后在子类中覆盖它以生成子类需要的任何额外输入并返回子类的新实例。

public class MyImmutable
{
// other stuff

// add this method
protected virtual MyImmutable GetNew(Dictionary<ImmutableKey, decimal> d)
{
return new MyImmutable(d);
}

// modify this method as shown
public MyImmutable Apply(Func<decimal, decimal, decimal> aggFunc, MyImmutable y)
{
var aggregated = new Dictionary<ImmutableKey, decimal>(AllKeys.Count());
foreach (ImmutableKey bt in AllKeys)
{
aggregated[bt] = aggFunc(this[bt], y[bt]);
}
return GetNew(aggregated);
}
}

public class SubImmutable : MyImmutable
{
// other stuff

// add this method
protected override MyImmutable GetNew(Dictionary<ImmutableKey, decimal> d)
{
return new SubImmutable(SomeOtherValue, d);
}
}

这样,任何不关心子类额外内容的转换都不需要在子类中被覆盖。

一些转换可能仍然需要被覆盖。例如:

var one = new SubImmutable(1, alpha);
var two = new SubImmutable(2, alpha);
var test1 = one.Apply((a, b) => a + b, two);
var test2 = two.Apply((a, b) => a + b, one);
Console.WriteLine(test1[someKey] == test2[someKey]); // true
Console.WriteLine(test1.SomeOtherValue == test2.SomeOtherValue); // false

如果您希望 test1test2 具有相同的 SomeOtherValue,那么您必须执行 Apply 方法虚拟,然后在子类中覆盖它。

关于C# 不可变类子类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28326884/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com