Extending a Delegate from a Base Class

Extending a delegate from a base class

I'd either create a wrapper delegate to make it the correct type in SubClass.

class SubClass: BaseClass {
var myDelegate: SubClassDelegate? {
get { return delegate as? SubClassDelegate }
set { delegate = newValue }
}
@IBAction func onDoSomething(sender: AnyObject) {
myDelegate?.additionalSubClassDelegateMethod();
}
}

Or simply cast the delegate to the expected type:

(delegate as? SubClassDelegate)?.additionalSubClassDelegateMethod();

Is it at all possible to extend System.Delegate?

Not with your own custom code, in C#. From section 10.1.4 of the C# 3.0 spec:

The direct base class of a class type
must not be any of the following
types: System.Array, System.Delegate,
System.MulticastDelegate, System.Enum,
or System.ValueType. Furthermore, a
generic class declaration cannot use
System.Attribute as a direct or
indirect base class.

However, every time you create a delegate type, that automatically derives from MulticastDelegate.

From ECMA-335, section 8.9.3:

While, for the most part, delegates
appear to be simply another kind of
user-defined class, they are tightly
controlled. The implementations of the
methods are provided by the VES, not
user code. The only additional members
that can be defined on delegate types
are static or instance methods.

That sounds like it's prohibiting constructors. I'd use a static method in a normal type instead, personally.

Using params in a Delegate as a base class

based on your updated code -- try this. As long as your method matches the delegate the contravariance should work as expected in .NET 3.5 or better

public abstract class SKConsoleParameter
{
protected string value;

public SKConsoleParameter(string value)
{
this.value = value;
}
public string GetRawValue()
{
return value;
}

public abstract bool IsValid();
public abstract object GetValue();
}

public class StringParam : SKConsoleParameter
{
public StringParam(string value) : base(value) { }

public override bool IsValid()
{
return true;
}

public override object GetValue()
{
return value;
}
}

public class IntParam : SKConsoleParameter
{
public IntParam(string value) : base(value) { }
public override bool IsValid()
{
int i;
return int.TryParse(value, out i);
}
public override object GetValue()
{
int i;
if (int.TryParse(value, out i))
return i;
else
return 0;
}
}

class Program
{

public delegate void CoolDelegate(params SKConsoleParameter[] parameters);

static void Main(string[] args)
{
var s = new StringParam("Glenn");
var i = new IntParam("12");
var coolDel = new CoolDelegate(DoSomethingCool);
coolDel(s, i);
}

public static void DoSomethingCool(params SKConsoleParameter[] parameters)
{
if (parameters == null) throw new ArgumentNullException("parameters");
foreach (var item in parameters)
{
if (item is IntParam)
{
// do something interesting
continue;
}

if (item is StringParam)
{
// do something else interesting
continue;
}

throw new NotImplementedException("unknown param type");
}
}
}

Delegate with base and/or inherited class parameter

Stumbled upon a blog that identified a solution that works. https://faithlife.codes/blog/2008/07/casting_delegates/

Excerpt from blog: "Fortunately, it is possible to cast between arbitrary delegate types, though it isn’t as efficient as you might like."

public static class DelegateUtility {
public static T Cast<T>(Delegate source) where T : class {
return Cast(source, typeof(T)) as T;
}
public static Delegate Cast(Delegate source, Type type) {
if (source == null)
return null;
Delegate[] delegates = source.GetInvocationList();
if (delegates.Length == 1)
return Delegate.CreateDelegate(type,
delegates[0].Target, delegates[0].Method);
Delegate[] delegatesDest = new Delegate[delegates.Length];
for (int nDelegate = 0; nDelegate < delegates.Length; nDelegate++)
delegatesDest[nDelegate] = Delegate.CreateDelegate(type,
delegates[nDelegate].Target, delegates[nDelegate].Method);
return Delegate.Combine(delegatesDest);
}
}

Using their utility class, i was able to cast the delegate type to it's base class which worked.

lstComplexThings [i].OnDoesStuff += DelegateUtility.Cast<Action<MyMoreComplexThing>>(callback);

Inject delegate method from derived to base class using constructor

The main thing I would suggest to change is:

  • to replace AnotherDelegateMethod and AnotherOneDelegateMethod passing (and then calling from parent class) with corresponding virtual methods.

As for another things, that all depends on the logic your class is suppose to implement. Possibly, some more decoupling might be needed.

  • new AnotherRepository(ADelegateMethod). That's really a tough question how to do everything right -- more info about general logic would be needed, as different approaches possible:

    • you can replace that also with virtual methods, like ADelegateMethod -- the same way as mentioned two above, but new AnotherRepository as protected virtual ISomeRepositoryInterface CreateRepositoryInstance() (for instance);
    • you can use dependency injection into some outside classes which would use your handler to pass the the repository, the same, actually, as Tools or another repository (but, again, everything depends on the general logic);

    • one of the ways to customize your handler(s) is to make the basic class as Generic and to inherit the children with providing some concrete class, which logic is related exactly to the inheritor, but mostly used only in parent class.

About events:

  • I would recommend you to read something like this and generally get familiar with Rx (Reactive Extensions) -- they are modern and awesome (you can consider using them instead of events in many cases (if not in this handler class, then in some other situations)). (However, currently I can't see the situation when you really would need to use events in your class).

Also, as for @durilka's answer (however, that's really funny to trust him considering his nickname "liar" from Russian, he he): he mentioned correctly (before I got into that) about:

  • to remove the nested class and replace with static constructor (if in base class). But that must be carefully rethinked (especially, if you really use multithreading widely).


Related Topics



Leave a reply



Submit