简体   繁体   中英

Make a generic delegate instance from a System.Type

Is there a way to have a delegate instance of an open generic type parameter like so?

Action<T> SomethingHappened;

The compiler is giving me an error.

I might have asked this question every 2 years and forgotten. I can't find a previous similar question, so I am asking away anyway.

What I am really trying to do is this:

In Entity Framework, I want that whenever some new rows are added to a table or some data in existing rows of a table is modified, I want to write a generic framework of publishers that may tell any interested listeners that such and such a thing has happened.

For eg a publisher may tell all listeners interested in knowing about any new row additions to the Customer table or any modification in the Customer table.

The listeners might be loggers, emailers, etc.

Currently, what I am doing is a kludge, but I would like a more type-safe solution. Here's what I am currently doing:

 public partial class DaEntities : ObjectContext
    {
        Action<object, ObjectStateEntry> EntityModified;
        Action<object, ObjectStateEntry> EntityDeleted;
        Action<object, ObjectStateEntry> EntityAdded;

    public override int SaveChanges(SaveOptions options)
        {
            var modifiedEntities = 
                 ObjectStateManager.GetObjectStateEntries(
                 System.Data.EntityState.Added | System.Data.EntityState.Modified);

            var deletedEntities = 
                 ObjectStateManager.GetObjectStateEntries(
                 System.Data.EntityState.Deleted);

            foreach (var entry in modifiedEntities)
            {
                var type = GetObjectType(entry.GetType());

                // fire delegates here
            }

            return base.SaveChanges(options);
        }
    }

In the above scenario, I'd rather like to have something like this:

public static Action<T, ObjectStateEntry> EntityModified;
public static Action<T, ObjectStateEntry> EntityDeleted;
public static Action<T, ObjectStateEntry> EntityAdded;

And have them point to a generic method like so:

public void SomethingHappenedToAnEntity<T, ObjectStateEntry>
    (T t, ObjectStateEntry e)
{
    // do stuff here
}

Having an undefined 'T' doesn't really make any sense... - what you really want is a custom event argument. You're going to have to force your types to be concrete at some point - so, you can either pass the parameter like:

Action<object> SomethingHappened;

And then have your code branch in the consuming method...

Or, you can cheat, and let dynamic dispatch try and figure out the types for you (at a small performance cost) - but this just pushes the problem around...

void Main()
{
    dynamic objectToProcess = new Moop();

    DoStuff(objectToProcess); //Dynamic dispatch will pick the best match automatically
}

public void DoStuff(Moop obj)
{
    Console.WriteLine(obj.GetType());
}

public void DoStuff(Gloop obj)
{
    Console.WriteLine(obj.GetType());
}

public void DoStuff(Bloop obj)
{
    Console.WriteLine(obj.GetType());
}

public class Moop {}
public class Gloop {}
public class Bloop {}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM