Если нужно бросать исключение (я бы бросал). С массивами ты ничего не сделаешь, чтобы нельзя было менять часть массива. Нужно использовать свой тип данных вместо массива, в котором и делать проверки.
using System;
namespace ConsoleApp1
{
public class ModelBase
{
protected bool CheckValueTypeField<T>(T field)
where T : struct
{
return field.Equals(default(T));
}
protected bool CheckReferenceTypeField<T>(T field)
where T : class
{
return field == null;
}
protected void ThrowIfNotDefault<T>(T field)
where T : struct
{
if (!CheckValueTypeField(field))
{
throw new InvalidOperationException();
}
}
protected void ThrowIfNotNull<T>(T field)
where T : class
{
if (!CheckReferenceTypeField(field))
{
throw new InvalidOperationException();
}
}
}
public class TestModel : ModelBase
{
private string _name;
private int _value;
public string Name
{
get { return _name; }
set
{
ThrowIfNotNull(_name);
_name = value;
}
}
public int Value
{
get { return _value; }
set
{
ThrowIfNotDefault(_value);
_value = value;
}
}
}
class Program
{
static void Main(string[] args)
{
var test = new TestModel();
test.Name = "test name";
test.Value = 1;
try
{
test.Name = "new name";
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
test.Value = 5;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Display(test);
}
static void Display(TestModel model)
{
Console.WriteLine(
$"{nameof(model.Name)} == {model.Name}; {nameof(model.Value)} == {model.Value};");
}
}
}
Можно, конечно, и так, но игнорировать изменения и никого об этом не уведомлять так себе затея.
public class TestModel : ModelBase
{
private string _name;
private int _value;
public string Name
{
get { return _name; }
set
{
if (!CheckReferenceTypeField(_name))
{
_name = value;
}
}
}
public int Value
{
get { return _value; }
set
{
if (!CheckValueTypeField(_value))
{
_value = value;
}
}
}
}
Или такой вариант, пока не определился с поведением, как определишься, можно удалить параметр из конструктора и часть поведения.
using System;
namespace ConsoleApp1
{
public abstract class ModelBase
{
private readonly bool _throwAnExceptionInsteadOfAnEvent;
public event EventHandler FieldIsNotDefault;
protected ModelBase(bool throwAnExceptionInsteadOfAnEvent = true)
{
_throwAnExceptionInsteadOfAnEvent = throwAnExceptionInsteadOfAnEvent;
}
protected bool CheckValueTypeField<T>(T field)
where T : struct
{
return field.Equals(default(T));
}
protected bool CheckReferenceTypeField<T>(T field)
where T : class
{
return field == null;
}
protected void AssertIsNotDefault<T>(T field)
where T : struct
{
if (!CheckValueTypeField(field))
{
if (_throwAnExceptionInsteadOfAnEvent)
{
throw new InvalidOperationException();
}
OnFieldIsNotDefault();
}
}
protected void AssertIsNotNull<T>(T field)
where T : class
{
if (!CheckReferenceTypeField(field))
{
if (_throwAnExceptionInsteadOfAnEvent)
{
throw new InvalidOperationException();
}
OnFieldIsNotDefault();
}
}
protected void OnFieldIsNotDefault()
{
FieldIsNotDefault?.Invoke(this, EventArgs.Empty);
}
}
public class TestModel : ModelBase
{
private string _name;
private int _value;
public string Name
{
get { return _name; }
set
{
AssertIsNotNull(_name);
_name = value;
}
}
public int Value
{
get { return _value; }
set
{
AssertIsNotDefault(_value);
_value = value;
}
}
public TestModel()
: base(false)
{
}
}
class Program
{
static void Main(string[] args)
{
var test = new TestModel();
test.FieldIsNotDefault += OnFieldIsNotDefault;
test.Name = "test name";
test.Value = 1;
try
{
test.Name = "new name";
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
try
{
test.Value = 5;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
test.FieldIsNotDefault -= OnFieldIsNotDefault;
Display(test);
}
private static void OnFieldIsNotDefault(object sender, EventArgs e)
{
Console.WriteLine("Поле уже установлено");
}
static void Display(TestModel model)
{
Console.WriteLine(
$"{nameof(model.Name)} == {model.Name}; {nameof(model.Value)} == {model.Value};");
}
}
}