Автоматическое свойство в зависимости от других свойствC#

Место общения программистов C#
Ответить
Anonymous
 Автоматическое свойство в зависимости от других свойств

Сообщение Anonymous »

Допустим, у меня есть это: < /p>
class AA(string a, string b, string? c) {
...
}

record BB {
public string A { get; init; };
public string B { get; init; };
public string? C { get; init; };
public string? D { get; init; };
}

Я хочу добавить AA в bb , чтобы он выглядел как:
record BB {
public string A { get; init; };
public string B { get; init; };
public string? C { get; init; };
public string? D { get; init; };
public AA Aa { get; } = new AA(A, B, C);
}

Но это не компилируется (я предполагаю, потому что члены Bb не инициализированы, пока AA строится.record BB {
public string A { get; init; };
public string B { get; init; };
public string? C { get; init; };
public string? D { get; init; };
private Lazy _Aa = new Lazy(new AA(A, B, C));
public AA Aa => _Aa.Value;
}

Я думал, что это должно работать, поскольку ленивый не будет вызовать новый aa (a, b, c) до тех пор, пока не будет вызван lazy.value , и AA и, в свою очередь, lazy.value не будет вызвана до тех пор, пока объективная инициализация BB завершится. Но компилятор не позволит мне использовать это, несмотря на то, что к тому времени, когда новый AA (...) можно назвать, , b и c уже были бы инициализированы. Идея): < /p>
record BB {
public string A { get; init; };
public string B { get; init; };
public string? C { get; init; };
public string? D { get; init; };
private AA? _Aa;
private readonly ReaderWriterLockSlim _AaLock = new();
public AA Aa
{
get
{
try
{
_AaLock.EnterReadLock();
if (_Aa == null)
{
try
{
_AaLock.EnterUpgradeableReadLock();
if (_Aa == null) {
try
{
_AaLock.EnterWriteLock();
_Aa = new(A, B, C);
}
finally
{
_AaLock.ExitWriteLock();
}
}
}
finally
{
_AaLock.ExitUpgradeableReadLock();
}

}
}
finally
{
_AaLock.ExitReadLock();
}
}
}
}
< /code>
Да, я знаю, что могу сделать все вышеперечисленное, если я не поддерживаю блок инициирования (т. Е. Используйте явный конструктор и установите все значения там). Просто интересно, есть ли способ сделать это при поддержке метода создания объектов init.var bb = new BB() {
A = "my A",
B = "my B",
C = "my C",
}
< /code>
против того, что я знаю, будет работать, но не поддержит приведенный выше метод создания блоков init: < /p>
var bb = new BB("my A", "my B", "my C", null);
// with constructor of BB being:
public BB(string a, string b, string? c, string? d) {
A = a;
B = b;
C = c;
D = d;
Aa = new AA(a, b, c);
}
< /code>

Обновление: я пометил решение Ивана Петрова, так как его единственное, что работало под моим тестированием.namespace ZZZ_CodeTest.Records
{
public record SomeRecordKey(string Field1, string Field2, string? Field3)
{
public string Field1 { get; init; } = Field1;
public string Field2 { get; init; } = Field2;
public string? Field3 { get; init; } = Field3;

}
}
< /code>
класс "Bb". < /p>
namespace ZZZ_CodeTest.Records
{
public record SomeRecord
{
protected SomeRecord(SomeRecord original)
{
_key = null;
this.Field1 = original.Field1; // when these
this.Field2 = original.Field2; // 4 lines were
this.Field3 = original.Field3; // missing, with
this.Field4 = original.Field4; // test did not pass.
}

private SomeRecordKey? _key;
public SomeRecordKey Key
{
get
{
// check docs for other overloads (incl. sync object)
LazyInitializer.EnsureInitialized(ref _key, () => new SomeRecordKey(Field1, Field2, Field3));
return _key;
}
}

public required string Field1 { get; init; }
public required string Field2 { get; init; }
public string? Field3 { get; init; }
public string? Field4 { get; init; }

}
}

< /code>
mStest class < /p>
namespace ZZZ_CodeTest.Records
{
[TestClass]
public sealed class SomeRecordTest
{
[TestMethod]
[DataRow("A", "B", null, null)]
[DataRow("A", "B", "C", null)]
[DataRow("A", "B", null, "D")]
[DataRow("A", "B", "C", "D")]
public void TestEquals(string field1, string field2, string? field3, string? field4)
{
SomeRecord sr1 = new()
{
Field1 = field1,
Field2 = field2,
Field3 = field3,
Field4 = field4,
};

SomeRecord sr2 = new()
{
Field1 = field1,
Field2 = field2,
Field3 = field3,
Field4 = field4,
};

Assert.AreEqual(sr1, sr2);
}

[TestMethod]
[DataRow("A", "B", null, null, "E")]
[DataRow("A", "B", "C", null, "E")]
[DataRow("A", "B", null, "D", "E")]
[DataRow("A", "B", "C", "D", "E")]
public void TestWith(string field1, string field2, string? field3, string? field4, string newField1)
{
SomeRecord sr = new()
{
Field1 = field1,
Field2 = field2,
Field3 = field3,
Field4 = field4,
};

Assert.AreEqual(sr.Field1, sr.Key.Field1);
Assert.AreEqual(sr.Field2, sr.Key.Field2);
Assert.AreEqual(sr.Field3, sr.Key.Field3);

SomeRecord mr = sr with
{
Field1 = newField1,
};

Assert.AreNotEqual(sr, mr);
Assert.AreNotEqual(sr.Key, mr.Key);

Assert.AreNotEqual(sr.Field1, mr.Field1);
Assert.AreEqual(sr.Field2, mr.Field2);
Assert.AreEqual(sr.Field3, mr.Field3);
Assert.AreEqual(sr.Field4, mr.Field4);

Assert.AreEqual(mr.Field1, newField1);
Assert.AreEqual(mr.Field1, mr.Key.Field1);
Assert.AreEqual(mr.Field2, mr.Key.Field2);
Assert.AreEqual(mr.Field3, mr.Key.Field3);
}

}
}


Подробнее здесь: https://stackoverflow.com/questions/796 ... properties
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»