I am stuck with a pattern for a long time now and recently I realized I forgot why I got used to do things this way.
public event EventHandler<string> SomethingChanged;
private void OnSomethingChanged(string something) => SomethingChanged?.Invoke(this, something);
So, when I want to invoke the event I call OnSomethingChanged(this, something);. Why not just do SomethingChanged?.Invoke(this, state); directly?
Feels like quite a simplification. Is it possible this OnSomethingChanged pattern served a purpose back then, when C# syntax was more complicated, but today it's mostly unnecessary?
In fact, since this pattern is quite long, I always just copy paste it and replace the relevant parts. Ironically, I can recall a couple of times when this copy pasting resulted debugging my software just to find out I made a mistake here, because of being in a hurry. This also makes invoking directly SomethingChanged preferable.
consider the following example:
public class BaseClass
{
private int id;
public int Id
{
get { return id; }
set { id = value; SomethingChanged(this, "id"); }
}
public event EventHandler<string> SomethingChanged;
}
public class DerivedClass : BaseClass
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
//// cannot be invoked directly here
// SomethingChanged(this, "name");
}
}
}
c# documentations mentions this case specifically
Events are a special type of delegate that can only be invoked from within the class that declared them. Derived classes cannot directly invoke events that are declared within the base class. Although sometimes you may want an event that can only be raised by the base class, most of the time, you should enable the derived class to invoke base class events. To do this, you can create a protected invoking method in the base class that wraps the event. By calling or overriding this invoking method, derived classes can invoke the event indirectly.
private method in the base class which triggeres event isn't much help, it should be protected. It is also sensible to make that method virtual to allow derived class add some functionality before/after notifing event subscrivers:
public class BaseClass
{
private int id;
public int Id
{
get { return id; }
set { id = value; OnSomethingChanged( "id"); }
}
public event EventHandler<string> SomethingChanged;
protected virtual void OnSomethingChanged(string something)
{
SomethingChanged(this, something);
}
}
public class DerivedClass : BaseClass
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnSomethingChanged("name");
}
}
protected override void OnSomethingChanged(string something)
{
base.OnSomethingChanged(something + " (event triggered from derived class)");
}
}
public static void Main(string[] args)
{
var item = new DerivedClass();
item.SomethingChanged += (e,s) => Console.WriteLine(s);
item.Id = 5;
item.Name = "abc";
}
this modified example prints:
id (event triggered from derived class)
name (event triggered from derived class)
Related
Say I have the class MyObject:
public class MyObject
{
public SomeOtherObject SomeOtherObject { get; set; }
public void MyMethod()
{
//Do something
}
}
Where MyObject.SomeOtherObject is as follows:
public class SomeOtherObject
{
public string Information { get; set; }
}
Assume that the property SomeOtherObject.Information is set by an instance of another class.
How can I automatically invoke MyObject.MyMethod() when MyObject.SomeOtherObject.Information changes?
Define an event callback. In SomeOtherObject;
public EventCallback OnInformationChangedEvent { get; set; }
I am not sure exactly what is setting the Information property. But ultimately you need a line somewhere in you SomeOtherObject class that does this;
await OnInformationChangedEvent.InvokeAsync();
You could even do this in the setter of the property itself.
In the parent MyObject you can pass the method that you want to be invoked. And refine your method as follows;
public void MyMethod(object sender, EventArgs e)
{
//Do something
}
And where you define SomeOtherObject;
SomeOtherObject.OnInformationChangedEvent += MyMethod;
There are other ways to do it (for example defining your own Observer pattern, which I think is what .NET is doing underneath anyway).
I didn't run that code so my syntax might be slightly off, but you should be 99% there with that.
I recommend using events. In the class MyObject, you can specify an event and register an event handler for this event - either use MyMethod as event handler or create another method that calls MyMethod.
Then, rewrite SomeOtherObject:
public class SomeOtherObject
{
public string Information
{
get => _Information;
set
{
_Information = value;
// add code to fire the event
}
}
private string _Information;
}
is there anyway to do something similar to what ive got bellow.
What im trying to do is to invoke a list of delegates at a specific point in time and keep track of them, and for the sake of keeping code clean, keep the delegates to be invoked in a list of some sort.
public interface IServiceStatusDelegate
{
object DynamicInvoke(object[] args)
}
public class ServiceStatusDelegate
: Delegate, IServiceStatusDelegate
{
}
public class MyServiceStatusCheckedDelegate
: ServiceStatusDelgate
{
}
public class MyServiceStatusChangedDelegate
: ServiceStatusDelgate
{
}
public class MyClass
{
public ServiceStatusDelgate[] listOfDelegatesToInvoke;
public void InvokeRequiredDelegates()
{
foreach(ServiceStatusDelegate delegateToInvoke in this.listOfDelegatesToInvoke)
delegateToInvoke.DynamicInvoke(new object[]{this, DateTime.Now});
}
}
You don't need a list of delegates... any delegate you create in c# is going to be multicast, so all you need is any delegate, and you can combine them with +. Just invoke it and all targets will be reached. For example:
Action target = null;
...
target += Method1;
...
target += Method2;
...
if(target != null) target(); // calls Method1 and Method2
This could (although it isn't necessary for it to stand) be implemented via an event which will make the convention very obvious the caller.
I have the following class that lets certain objects subscribe to a change event. The problem is that I also have classes B, and C that need this functionality that allow objects to subscribe to the same kind of thing. We certainly don't want to copy and paste this behaviour.
We've considered inheriting from a common base class, but all our classes including A, B, and C already inherit from a common BaseClass. And we don't want to add this behaviour to BaseClass because our other classes E,F,G that inherit from BaseClass don't need this behaviour.
Is there a better solution?
public class A : BaseClass
{
/*other properties and code */
public event EventHandler OnChange;
private bool _hasChanged;
public bool HasChanged
{
get { return _hasChanged; }
set
{
_hasChanged = value;
//only need to notify when we've changed.
if (value)
{
if (OnChange != null)
OnChange(this, EventArgs.Empty);
}
}
}
}
Consider an aspect-oriented programming approach, like the one used in this PostSharp example. It would allow you to inject that kind of boilerplate code using attributes.
If you created the appropriate aspect, you could then have code like:
public class A : BaseClass
{
public event EventHandler OnChanged;
[ChangedNotify("OnChanged")]
public bool HasChanged { get; set; }
}
or, if the idea is to have a single OnChange event for multiple properties, you could just hard-code that into the aspect, reducing your code to
public class A : BaseClass
{
[NotifyOnChanged]
public bool HasChanged { get; set; }
}
What if we don't use inheritance for a moment?
1- Suppose , Instead of inheriting from a common base class, Compose your client class which requires event mechanism with a object which implement event mechanism.
Suppose our class is
public class EventNotifier
{
public event EventHandler OnChange;
private bool _hasChanged;
public bool HasChanged
{
get { return _hasChanged; }
set
{
_hasChanged = value;
//only need to notify when we've changed.
if (value)
{
if (OnChange != null)
OnChange(this, EventArgs.Empty);
}
}
}
}
2-
public class A
{
private EventNotifier eventNotifier;
public EventNotifier MyEventNotifier { get { return eventNotifier; } }
public A()
{
eventNotifier = new EventNotifier();
}
}
3- Now your users of class A ( class which is inherited / composed class A)
this is for if B contains A
public class b
{
A obj ;
public b()
{
obj = new A();
obj.MyEventNotifier.OnChange += new EventHandler(delegate { Console.WriteLine("Hi"); });
obj. MyEventNotifier.HasChanged = true;
}
}
You could consider introducing an intermediary class between BaseClass and A,B,C that contains the common behaviour. In this way you will not be polluting E,F,G which do not need the behaviour.
BaseClass
-----------------------------
| |
----- NotifyBaseClass
E,F,G |
-----
A,B,C
NB Although AOP looks yummy I have had major problems trying to get Postsharp to work with other technologies e.g. MS Code Analysis and MSBuild.
Having a subclass for notifyable objects might be the way to go but it can be tricky with aspects multiplying that way into a wide range of different classes. Another way would to infact include it in your base class and define an interface for it, then you can simply tack on the interface for the relevant classes.
When running yous simply check if it's a IChangeable (or something) and only hook up to the event then
In my app, I wanted to let class B get some information from class A but as A instantionates B, B has no reference to A (intentionally).
I have never used events for that purpose so I am not sure whether its correct, but it works:
class A
{
public delegate bool GetFromB();
public event GetFromB GetDataFromB;
...
//get data from B without having an access to it
bool Result=GetDataFromB();
}
class B
{
A a=new A();
A.GetDataFromB=new A.GetFromB(DO_THAT);
public bool DO_THAT()
{
...
return true; //and that is it, it will return to event caller
}
}
It'll certainly work, and that approach is used in a few places in the core framework - AssemblyResolve etc. Alternative approaches here:
if it is used by a method, pass it into the method as a callback delegate. Same approach, but simply not exposed as an event
ditto, but with an interface
but it'll work that way. It isn't unheard of. Code tweaks, though:
A a=new A();
a.GetDataFromB=+new A.GetFromB(DO_THAT);
you subscribe on the instance (unless it is static), and need +=, not =.
Also: consider using Func<bool> rather than declaring your own delegate type.
Don't do that. Events implies that multiple listeners can be used, and it looks like you are not handling return values from multiple listeners. You can do that by traversing myevent.GetInvocationList() and invoke each listener separately.
Use a simple delegate instead:
class A
{
public delegate bool GetFromB();
public GetFromB GetDataFromB { get; set; }
}
The other standard way is to have event arguments that provide a property for return value.
class MyEventArgs : EventArgs
{
public bool ReturnValue {get; set; }
// and something more here.
}
public class A
{
public event EventHandler<MyEventArgs> MyEvent;
}
As you wrote, A currently instanciates B so, you should not change this by creating an instance of A in B.
If B needs several different data from A, you can let A realize some IBNeededData interface. If B needs only one call on A, the straight forward solution would be a callback method.
Edit
Here's a sample for the callback. (Hope you are fine with the lambda expression to provide the data from A.)
[TestClass]
public class UnitTest1 {
class A {
public void DoWork() {
B b = new B();
//b.GetData = () => "Some data";
Func<string> callback = new Func<string>(this.GetBData);
b.GetData = callback;
b.DoBWork();
}
private string GetBData() {
return "Some data";
}
}
class B {
public Func<string> GetData { get; set; }
public void DoBWork() {
string data = GetData();
Console.WriteLine("Working with {0}", data);
}
}
[TestMethod]
public void TestMethod1() {
A a = new A();
a.DoWork();
}
}
C# - .net 3.5
I have a family of classes that inherit from the same base class.
I want a method in the base class to be invoked any time a property in a derrived class is accessed (get or set). However, I don't want to write code in each and every property to call the base class... instead, I am hoping there is a declarative way to "sink" this activity into the base class.
Adding some spice to the requirement, I do need to determine the name of the property that was accessed, the property value and its type.
I imagine the solution would be a clever combination of a delegate, generics, and reflection. I can envision creating some type of array of delegate assignments at runtime, but iterating over the MemberInfo in the constructor would impact performance more than I'd like. Again, I'm hoping there is a more direct "declarative" way to do this.
Any ideas are most appreciated!
You can't do it automatically, but you can pretty much get 95% for free. This is a classic case for aspect-oriented programming. Check out PostSharp, which has the OnFieldAccessAspect class. Here's how you might solve your problem:
[Serializable]
public class FieldLogger : OnFieldAccessAspect {
public override void OnGetValue(FieldAccessEventArgs eventArgs) {
Console.WriteLine(eventArgs.InstanceTag);
Console.WriteLine("got value!");
base.OnGetValue(eventArgs);
}
public override void OnSetValue(FieldAccessEventArgs eventArgs) {
int i = (int?)eventArgs.InstanceTag ?? 0;
eventArgs.InstanceTag = i + 1;
Console.WriteLine("value set!");
base.OnSetValue(eventArgs);
}
public override InstanceTagRequest GetInstanceTagRequest() {
return new InstanceTagRequest("logger", new Guid("4f8a4963-82bf-4d32-8775-42cc3cd119bd"), false);
}
}
Now, anything that inherits from FieldLogger will get the same behavior. Presto!
I don't believe this is possible to do declaratively, i have never seen it done that way. What you can do though is implement the INotifyPropertyChanged interface on your base class, and have the implementation of the interface in the base class. Something like this:
public class A : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
protected virtual void RaiseOnPropertyChanged(object sender, string propertyName)
{
if (this.PropertyChanged != null)
PropertyChanged(sender, new PropertyChangedEventArgs(propertyName);
}
public A()
{
this.PropertyChanged += new PropertyChangedEventHandler(A_PropertyChanged);
}
void A_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//centralised code here that deals with the changed property
}
}
public class B : A
{
public string MyProperty
{
get { return _myProperty; }
set
{
_myProperty = value;
RaiseOnPropertyChanged(this, "MyProperty");
}
}
public string _myProperty = null;
}