参考对象并在事件

时间:2015-07-18 13:49:06

标签: c#

我有一个更理论化的问题,希望你能帮助我。

想象一下,你有以下课程:

public class Foo
{
    public event EventHandler Invalid;
    //some more Properties/Fields/Methods and stuff but only the event is important for my question
}

现在你还有两个类,一个初始化这个对象并使用另一个“监视”对象并执行其他操作的类:

public class Bar
{
    private Foo _foo;
    public void Main()
    {
        _foo = new Foo();
        FooUtils.RegisterFoo(_foo);

        //do some stuff with foo...
    }
}

public static class FooUtils
{
    public static void RegisterFoo(Foo foo)
    {
        foo.Invalid -= OnInvalid;
        foo.Invalid += OnInvalid;
    }

    private static void OnInvalid(object sender, EventArgs args)
    {
        var foo = sender as Foo;
        if (foo != null)
        {
            //do some stuff...
        }
    }
}

我想扩展FooUtils,在某些情况下它可以创建一个新的Foo实例,所以我认为“嘿没有问题只是将其作为参考传递。”,所以我将代码更改为以下... < / p>

public class Bar
{
    private Foo _foo;
    public void Main()
    {
        _foo = new Foo();
        //do some stuff with foo...

        FooUtils.RegisterFoo(ref _foo);
    }
}

public static class FooUtils
{
    public static void RegisterFoo(ref Foo foo)
    {
        foo.Invalid -= OnInvalid;
        foo.Invalid += OnInvalid;
    }

    private static void OnInvalid(object sender, EventArgs args)
    {
        var foo = sender as Foo;
        if (foo != null)
        {
            //do some stuff...

            //create a new Instance and set it to ?!?
            var helpMe = new Foo();
        }
    }
}

如果我在Register方法中实例化一个新的Foo,但是我需要在事件内部创建一个新实例(在var helpMe = new Foo();),行,我将如何做到这一点,这个代码可以工作?那么最后这个字段bar内的_foo会更新吗?请记住,我可以在静态 FooUtils中注册几个Foos,并根据注册的Foo触发Invalid事件,相应的引用应该更新。这是否可能,如果没有什么是一个好的选择?

只是为了确保:是的,我知道我可以在Bar内部听取事件并将_foo字段设置在bar内部但是如果可能的话我想保持这种分离。

2 个答案:

答案 0 :(得分:1)

您可以使用委托指向发件人通过引用传递的方法替换EventHandler类中的Foo

public class Foo
{
    public delegate void InvalidEventHandler(ref Foo sender, EventArgs args);
    public event InvalidEventHandler Invalid;
}

然后您需要更改OnInvalid方法:

private static void OnInvalid(ref Foo sender, EventArgs args)
{
    if (sender != null)
    {
        //do some stuff...

        sender = new Foo();
    }
}

现在,在调用该方法时,您需要通过引用传递Foo,并且Foo类中的Boo对象可以看到更改。

答案 1 :(得分:1)

你可以这样做:

public class Bar
{
    private Foo _foo;
    public void Main()
    {
        _foo = new Foo();
        //do some stuff with foo...

        FooUtils.RegisterFoo(_foo, ReferenceChanger);
    }

    public void ReferenceChanger (Foo anotherFoo)
    {
        _foo = anotherFoo;
    }
}

public class Foo
{
    public event EventHandler Invalid;
    //some more Properties/Fields/Methods and stuff but only the event is important for my question
}

public static class FooUtils
{
    private static Dictionary<Foo, Action<Foo>> actionsToCallDictionary;
    public static void RegisterFoo( Foo foo, Action<Foo> changeReferenceAction)
    {
        foo.Invalid -= OnInvalid;

        if (actionsToCallDictionary != null)
            actionsToCallDictionary.Remove(foo);

        foo.Invalid += OnInvalid;

        if (actionsToCallDictionary == null)
            actionsToCallDictionary = new Dictionary<Foo, Action<Foo>>();

        actionsToCallDictionary[foo] = changeReferenceAction;

    }

    private static void OnInvalid(object sender, EventArgs args)
    {
        var foo = sender as Foo;
        if (foo != null)
        {
            //do some stuff...

            //create a new Instance and set it to ?!?
            Action<Foo> referenceChanger;
            if (actionsToCallDictionary != null && actionsToCallDictionary.TryGetValue(foo, out referenceChanger))
            {
                var changeWith = new Foo();
                referenceChanger(changeWith);
            }
        }
    }
}

但请注意,如果您不小心处理/管理该静态字典,可能会以内存泄漏结束。

另一个问题是在多线程环境中,您应该锁定/解锁该字典。