16

I have a user control which deals with fileupload. I have defined a delegate as follows

public delegate void FileUploadSuccess<T>(T value,FileUploadType F)

value can be a string as well as byte array. FileUploadType is an enum which tells which type of file was uploaded.

Now I have declared a event in usercontrol to raise this.

public event FileUploadSuccess<string> successString;   //In case I want a file name

public event FileUploadSuccess<Byte[]> successStringImage;  // In case I want a byte[] of uploaded image

What I wanted was a generic event

public event FileUploadSuccess<T> successString. 
wonea
  • 4,783
  • 17
  • 86
  • 139
Rohit Raghuvansi
  • 2,824
  • 8
  • 46
  • 74

6 Answers6

18

Except as part of generic types (i.e.

class Foo<T> { public event SomeEventType<T> SomeEventName; }

) there is no such thing as generic properties, fields, events, indexers or operators (only generic types and generic methods). Can the containing type here be generic?

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
6

To the outside world, an event in many ways looks like a field of the class. Just as you can't use an open generic type to declare a field, you can't use an open generic type to declare an event.

If you could leave the type open, then the compiler would have to compile in the event handler add and remove code for every possible type for your generic parameter T. A closed generic type can't be JIT compiled, because your event is not a type in its own right, rather is a part of an enclosing type.

David M
  • 71,481
  • 13
  • 158
  • 186
6

That's impossible unless you define your type parameter in an enclosing class. For example:

public delegate void FileUploadSuccess<T>(T value, FileUploadType F)

public class FileUploader<T>
{
    public event FileUploadSuccess<T> FileUploaded;
}

But this only moves your problem to another location, since now you would have to declare two instances of the FileUploader class:

FileUploader<string> stringUploader = new FileUploader<string>();
FileUploader<byte[]> stringUploader = new FileUploader<byte[]>();

This may not be what you want.

Ronald Wildenberg
  • 31,634
  • 14
  • 90
  • 133
2

Why do you need a generic event? Can't you just use a normal event:

public delegate void FileUploadSuccess(object value);

and then

public event FileUploadSuccess Success;

In the Success event handler you will know the type of the object being passed:

public void SuccessHandler(object value)
{
    // you know the type of the value being passed here
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
0

I don't think this is possible.

Event is like an instance of a delegate (roughly speaking), and an instance is a concrete implementation ( of a generic or a non-generic class).

For better understanding of delegates and event, you can refer to this SO discussion.

Community
  • 1
  • 1
Manish Basantani
  • 16,931
  • 22
  • 71
  • 103
-1

There is a generic EventHandler class in the .Net Framework just for this purpose:

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Counter c = new Counter(new Random().Next(10));
            c.ThresholdReached += c_ThresholdReached;

            Console.WriteLine("press 'a' key to increase total");
            while (Console.ReadKey(true).KeyChar == 'a')
            {
                Console.WriteLine("adding one");
                c.Add(1);
            }
        }

        static void c_ThresholdReached(object sender, ThresholdReachedEventArgs e)
        {
            Console.WriteLine("The threshold of {0} was reached at {1}.", e.Threshold,  e.TimeReached);
            Environment.Exit(0);
        }
    }

    class Counter
    {
        private int threshold;
        private int total;

        public Counter(int passedThreshold)
        {
            threshold = passedThreshold;
        }

        public void Add(int x)
        {
            total += x;
            if (total >= threshold)
            {
                ThresholdReachedEventArgs args = new ThresholdReachedEventArgs();
                args.Threshold = threshold;
                args.TimeReached = DateTime.Now;
                OnThresholdReached(args);
            }
        }

        protected virtual void OnThresholdReached(ThresholdReachedEventArgs e)
        {
            EventHandler<ThresholdReachedEventArgs> handler = ThresholdReached;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        public event EventHandler<ThresholdReachedEventArgs> ThresholdReached;
    }

    public class ThresholdReachedEventArgs : EventArgs
    {
        public int Threshold { get; set; }
        public DateTime TimeReached { get; set; }
    }
}

source: https://learn.microsoft.com/en-us/dotnet/api/system.eventhandler-1

William Leader
  • 814
  • 6
  • 20