Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 设置对象的所有属性时是否存在事件?_C#_.net_Events - Fatal编程技术网

C# 设置对象的所有属性时是否存在事件?

C# 设置对象的所有属性时是否存在事件?,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

想象一个简单的POCO

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开始时,有些情况是合理的