c# - Mixing Covariance and Contravariance -
goal:
iterate on following collection
var collection = new iimporttrigger<eventargs>[] { new filesystemimporttrigger() , new timerimporttrigger() };
in way
foreach (var trigger in collection) { trigger.import += trigger.onimport; }
this have far
public delegate void importtriggereventhandler<in t>(object sender, t args) t : eventargs; public interface iimporttrigger<out t> t : eventargs { event importtriggereventhandler<t> import; void onimport<t1>(object sender, t1 args) t1 : eventargs; } public class filesystemimporttrigger : iimporttrigger<filesystemeventargs> { public event importtriggereventhandler<filesystemeventargs> import; public void onimport<t>(object sender, t args) t : eventargs { } } public class timerimporttrigger : iimporttrigger<elapsedeventargs> { public event importtriggereventhandler<elapsedeventargs> import; public void onimport<t>(object sender, t args) t : eventargs { } }
expectations:
i define iimporttrigger 1 generic parameter.
problem:
if change interface definition following (notice generic argument t not covariant more).
public interface iimporttrigger<t> t : eventargs { event importtriggereventhandler<t> import; void onimport(object sender, t args); }
and hence
public class filesystemimporttrigger : iimporttrigger<filesystemeventargs> { public event importtriggereventhandler<filesystemeventargs> import; public void onimport(object sender, filesystemeventargs args) { } } public class timerimporttrigger : iimporttrigger<elapsedeventargs> { public event importtriggereventhandler<elapsedeventargs> import; public void onimport(object sender, elapsedeventargs args) { } }
i wont able create common type collection
var collection = new iimporttrigger<eventargs>[] { new filesystemimporttrigger() , new timerimporttrigger() };
because generic parameter not output-safe more.
question:
is there way accomplish scenario?
by switching onimport not generic @ use explicit interface, make more derived interface not covariant has generic verson of onimport pull off.
internal class program { private static void main(string[] args) { var collection = new iimporttriggerbase<eventargs>[] { new filesystemimporttrigger() , new timerimporttrigger() }; foreach (var trigger in collection) { trigger.import += trigger.onimport; } } } public delegate void importtriggereventhandler<in t>(object sender, t args) t : eventargs; public interface iimporttriggerbase<out t> t : eventargs { event importtriggereventhandler<t> import; void onimport(object sender, eventargs args); } public interface iimporttrigger<t> : iimporttriggerbase<t> t : eventargs { void onimport(object sender, t args); } public class filesystemimporttrigger : iimporttrigger<filesystemeventargs> { public event importtriggereventhandler<filesystemeventargs> import; public void onimport(object sender, filesystemeventargs args) { } void iimporttriggerbase<filesystemeventargs>.onimport(object sender, eventargs args) { onimport(sender, (filesystemeventargs)args); } } public class timerimporttrigger : iimporttrigger<elapsedeventargs> { public event importtriggereventhandler<elapsedeventargs> import; public void onimport(object sender, elapsedeventargs args) { } void iimporttriggerbase<elapsedeventargs>.onimport(object sender, eventargs args) { onimport(sender, (elapsedeventargs)args); } }
however give cruft of onimport(object sender, eventargs args)
method visible on iimporttrigger<t>
.
that solve problem, if going , assuming correctly want derived classes able pick on fact import
getting fired , not need onimport exposed
internal class program { private static void main(string[] args) { var collection = new iimporttrigger<eventargs>[] { new filesystemimporttrigger() , new timerimporttrigger() }; } } public delegate void importtriggereventhandler<in t>(object sender, t args) t : eventargs; public interface iimporttrigger<out t> t : eventargs { event importtriggereventhandler<t> import; } public abstract class onimportbase<t> : iimporttrigger<t> t: eventargs { public event importtriggereventhandler<t> import; protected virtual void onimport(object sender, t args) { var tmp = import; if (tmp != null) { tmp(this, args); } } } public class filesystemimporttrigger : onimportbase<filesystemeventargs> { protected override void onimport(object sender, filesystemeventargs args) { dosomeextrastuffbeforeimport(); base.onimport(sender, args); } private void dosomeextrastuffbeforeimport() { } } public class timerimporttrigger : onimportbase<elapsedeventargs> { protected override void onimport(object sender, elapsedeventargs args) { base.onimport(sender, args); dosomeextrastuffafterimport(); } private void dosomeextrastuffafterimport() { } }
this gets rid of event subscription , instead handles override (which normal pattern in .net events).
Comments
Post a Comment