C# 设置对象的所有属性时是否存在事件?
想象一个简单的POCOC# 设置对象的所有属性时是否存在事件?,c#,.net,events,C#,.net,Events,想象一个简单的POCO public class Test{ public int ID {get; set;} public string Name {get; set;} public string SomeProperty {get; set;} } 是否有方法将此对象连接起来,使事件仅在设置了所有属性后才会触发?像是一个初始化完成的事件还是什么?或者,有没有一种方法可以轻松创建这样的事件自定义 谢谢您可以自己这样实现: public delegate void
public class Test{
public int ID {get; set;}
public string Name {get; set;}
public string SomeProperty {get; set;}
}
是否有方法将此对象连接起来,使事件仅在设置了所有属性后才会触发?像是一个初始化完成的事件还是什么?或者,有没有一种方法可以轻松创建这样的事件自定义
谢谢您可以自己这样实现:
public delegate void AllPropertiesSetDelegate();
public class Test
{
public delegate void AllPropertiesSetDelegate(object sender, EventArgs args);
public int Id
{
get => _id;
set
{
_id = value;
CheckAllProperties();
}
}
private int _id;
public string Name
{
get => _name;
set
{
_name = value;
CheckAllProperties();
}
}
private string _name;
private void CheckAllProperties()
{
//Comparing Id to null is pointless here because it is not nullable.
if (Name != null && Id != null)
{
AllPropertiesSet?.Invoke(this, new EventArgs());
}
}
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.AllPropertiesSet += delegate { AllPropsSet(); };
t.Id = 1;
t.Name = "asd";
Console.ReadKey();
}
static void AllPropsSet()
{
Console.WriteLine("All properties have been set.");
}
}
亲自看看您是否可以让实现变得更小/更轻松地处理
测试代码:
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.AllPropertiesSet += delegate { AllPropsSet(); };
t.Id = 1;
t.Name = "asd";
Console.ReadKey();
}
static void AllPropsSet()
{
Console.WriteLine("All properties have been set.");
}
}
以下是如何使用反射检查所有非值类型是否为null:
public static bool AllPropertiesNotNull<T>(this T obj) where T : class
{
foreach (var prop in obj.GetType().GetProperties())
{
//See if our property is not a value type (value types can't be null)
if (!prop.PropertyType.IsValueType)
{
if (prop.GetValue(obj, null) == null)
{
return false;
}
}
}
return true;
}
您可以自己这样实现:
public delegate void AllPropertiesSetDelegate();
public class Test
{
public delegate void AllPropertiesSetDelegate(object sender, EventArgs args);
public int Id
{
get => _id;
set
{
_id = value;
CheckAllProperties();
}
}
private int _id;
public string Name
{
get => _name;
set
{
_name = value;
CheckAllProperties();
}
}
private string _name;
private void CheckAllProperties()
{
//Comparing Id to null is pointless here because it is not nullable.
if (Name != null && Id != null)
{
AllPropertiesSet?.Invoke(this, new EventArgs());
}
}
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.AllPropertiesSet += delegate { AllPropsSet(); };
t.Id = 1;
t.Name = "asd";
Console.ReadKey();
}
static void AllPropsSet()
{
Console.WriteLine("All properties have been set.");
}
}
亲自看看您是否可以让实现变得更小/更轻松地处理
测试代码:
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.AllPropertiesSet += delegate { AllPropsSet(); };
t.Id = 1;
t.Name = "asd";
Console.ReadKey();
}
static void AllPropsSet()
{
Console.WriteLine("All properties have been set.");
}
}
以下是如何使用反射检查所有非值类型是否为null:
public static bool AllPropertiesNotNull<T>(this T obj) where T : class
{
foreach (var prop in obj.GetType().GetProperties())
{
//See if our property is not a value type (value types can't be null)
if (!prop.PropertyType.IsValueType)
{
if (prop.GetValue(obj, null) == null)
{
return false;
}
}
}
return true;
}
如果要确保正确创建对象,为什么不将其设置为创建对象的唯一方法是同时设置所有属性
public class Test{
public int ID {get; set;}
public string Name {get; set;}
public string SomeProperty {get; set;}
// Constructor
public Test(int id, string Name, string someProperty)
{
this.ID = id;
this.Name = name;
this.SomeProperty = someProperty;
}
}
如果要确保正确创建对象,为什么不将其设置为创建对象的唯一方法是同时设置所有属性
public class Test{
public int ID {get; set;}
public string Name {get; set;}
public string SomeProperty {get; set;}
// Constructor
public Test(int id, string Name, string someProperty)
{
this.ID = id;
this.Name = name;
this.SomeProperty = someProperty;
}
}
这里是@fstam答案的一个变体。它将此更改为完全打开
事件
,并调用以检查属性。如果你投票给我,投票给@fstam
第一节课:
public class TestPropertyCheck
{
public event EventHandler AllPropertiesSet;
public int Id
{
get => _id;
set
{
_id = value;
CheckAllProperties(PropertyNames.Id);
}
}
private int _id;
public string Name
{
get => _name;
set
{
_name = value;
CheckAllProperties(PropertyNames.Name);
}
}
private string _name;
public string Address
{
get => _address;
set
{
_address = value;
CheckAllProperties(PropertyNames.Address);
}
}
private string _address;
private void CheckAllProperties(PropertyNames propName)
{
propertiesSet |= propName;
if (propertiesSet == PropertyNames.AllProps)
{
AllPropertiesSet?.Invoke(this, new EventArgs());
}
}
private PropertyNames propertiesSet = PropertyNames.None;
[Flags]
private enum PropertyNames
{
None = 0,
Id = 0x01,
Name = 0x02,
Address = 0x04,
AllProps = Id | Name | Address,
}
}
然后是一个测试程序
public static class PropertyCheckTester
{
public static void Test()
{
var test = new TestPropertyCheck();
test.AllPropertiesSet += AllPropertiesSet;
Debug.WriteLine("Setting Name");
test.Name = "My Name";
Debug.WriteLine("Setting ID");
test.Id = 42;
Debug.WriteLine("Setting Address");
test.Address = "Your address goes here";
}
public static void AllPropertiesSet(object sender, EventArgs args)
{
Debug.WriteLine("All Properties Set");
}
}
以及输出:
Setting Name
Setting ID
Setting Address
All Properties Set
这里是@fstam答案的一个变体。它将此更改为完全打开
事件
,并调用以检查属性。如果你投票给我,投票给@fstam
第一节课:
public class TestPropertyCheck
{
public event EventHandler AllPropertiesSet;
public int Id
{
get => _id;
set
{
_id = value;
CheckAllProperties(PropertyNames.Id);
}
}
private int _id;
public string Name
{
get => _name;
set
{
_name = value;
CheckAllProperties(PropertyNames.Name);
}
}
private string _name;
public string Address
{
get => _address;
set
{
_address = value;
CheckAllProperties(PropertyNames.Address);
}
}
private string _address;
private void CheckAllProperties(PropertyNames propName)
{
propertiesSet |= propName;
if (propertiesSet == PropertyNames.AllProps)
{
AllPropertiesSet?.Invoke(this, new EventArgs());
}
}
private PropertyNames propertiesSet = PropertyNames.None;
[Flags]
private enum PropertyNames
{
None = 0,
Id = 0x01,
Name = 0x02,
Address = 0x04,
AllProps = Id | Name | Address,
}
}
然后是一个测试程序
public static class PropertyCheckTester
{
public static void Test()
{
var test = new TestPropertyCheck();
test.AllPropertiesSet += AllPropertiesSet;
Debug.WriteLine("Setting Name");
test.Name = "My Name";
Debug.WriteLine("Setting ID");
test.Id = 42;
Debug.WriteLine("Setting Address");
test.Address = "Your address goes here";
}
public static void AllPropertiesSet(object sender, EventArgs args)
{
Debug.WriteLine("All Properties Set");
}
}
以及输出:
Setting Name
Setting ID
Setting Address
All Properties Set
对于具有完整属性的普通类来说,此类事件相当容易实现(下面的代码来自@fstam的答案,部分来自head,告诉我是否有错误,或者将其作为伪代码进行威胁):
公共类测试
{
公共事件处理程序初始化完成;
内部id;
公共整数Id
{
get=>\u id;
设置
{
_id=值;
CheckAllProperties();
}
}
字符串\u名称;
公共字符串名
{
get=>\u name;
设置
{
_名称=值;
CheckAllProperties();
}
}
HashSet _initialized=new HashSet对于具有完整属性的普通类来说,这样的事件相当容易实现(下面的代码来自@fstam的答案,部分来自head,告诉我是否有错误,或者以伪代码的形式威胁它):
公共类测试
{
公共事件处理程序初始化完成;
内部id;
公共整数Id
{
get=>\u id;
设置
{
_id=值;
CheckAllProperties();
}
}
字符串\u名称;
公共字符串名
{
get=>\u name;
设置
{
_名称=值;
CheckAllProperties();
}
}
HashSet _initialized=new HashSet如果您允许POCO中的事件,那么向setter添加一些代码也可以。但它更多地用于控件。为了使其有用,创建对象的参与者必须调用EndInit
,这在DTO和likeX-Y-Question中是不可能的。您认为为什么需要这样的事件?您有过吗考虑过POCO中的INotifyPropertyChange吗?当PropertyChange触发时,您仍然需要一个方法来执行检查。以下是几个链接:如果您允许POCO中的事件,那么向setter添加一些代码也可以。但它更适合与控件一起使用。为了使其有用,创建对象的参与者必须调用EndInit
这在DTO和likeX-Y-Question中是不可能的。为什么您认为您需要这样一个事件?您考虑过POCO中的INotifyPropertyChange吗?当PropertyChange触发时,您仍然需要一个方法来执行检查。这是两个链接:@RandRandom谢谢,已修复。Name!=null&&Id!=null
是一个支持ort噩梦。作为一个想法:使用[CallerMemberName]
、反射和一些哈希表。您可能希望将标准事件签名(对象发送方、EventArgs args)添加到事件中。为了遵循@Sinatr所说的,您需要比双空检查更积极的东西。可能是[Flags]
enum参数添加到'CheckAllProperties`@Flydog57.@Sinatr不确定您将如何实现它。此代码可读,这通常是我的首选。无论如何,请随时提交代码编辑!@RandRandom谢谢,修复。Name!=null&&Id!=null
是一个支持噩梦。作为一个想法:使用[CallerMemberName]
、反射和一些哈希表。您可能希望将标准事件签名(对象发送方、事件args args)添加到事件中。为了遵循@Sinatr所说的,您需要比双重空检查更积极的内容。可能是[标志]
enum参数添加到'CheckAllProperties`@Flydog57。@Sinatr不确定您将如何实现它。这段代码可读,这通常是我的首选。无论如何,请随意提交代码编辑!我明白了,这也行。我有点不喜欢需要enum,但也许您可以使用反射来获取cla的所有可为空的属性ss并检查它们是否为null。这将使其更通用。尝试以下方法:枚举比使用反射便宜得多。是的,它需要维护(如果添加属性,则需要对枚举执行两项操作),但是,这些都隐藏在类中。我明白了,这也很有效。我有点不喜欢使用枚举,因为也许你可以使用反射来获取类的所有可为null的属性并检查它们是否为null。这会使它更通用。试着这样做:枚举比使用反射便宜得多。是的,它需要维护(如果您添加属性,您需要对枚举执行两件事),但是,这些都隐藏在类中。这当然是一个好模式,我也是如何编写自己的类的。但是,当我们需要从de开始时,有些情况是合理的