EventAggregator Helper Generic method - c#

Why this gives a compiler error?
public class EventAggregationHelper {
public static SubscriptionToken SubscribeToEvent<T>( IEventAggregator eventAggregator ) where T : EventBase {
T evt = eventAggregator.GetEvent<T>();
//T evt = eventAggregator.GetEvent<T>();
return null;
}
}
The error is:
Severity Code Description Project File Line Suppression State
Error CS0310 'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TEventType' in the generic type or method 'IEventAggregator.GetEvent()' EntitySetGridTWPF D:\DEVELOPER.NET\Comercial\EntityBookCommon\EntitySetGridTWPF\EventAggregation\EventAggregationHelper.cs 9 Active
on the line:
T evt = eventAggregator.GetEvent<T>();
I've used this approach for calling other generic methods before and has worked. What has GetEvent so special?
Thanks in advance.

IEventAggregator.GetEvent has a new() constraint, which means that your subscription also needs to add the new() constraint and that also needs to be fulfilled by your implementation class T, which must have a public parameterless (default) constructor (and must not be abstract.)
public static SubscriptionToken SubscribeToEvent<T>
(IEventAggregator eventAggregator) where T : EventBase, new() {

Related

Using Generic T of Method to create new instance of another object with the same Generic T

So I have a method which looks something like this
public void Register<T>(TimeSpan interval, ILogger logger) where T : ISchedule
{
_schedules.Add(new Schedule<T>(interval, logger));
}
I want to create a new Schedule with the T provided to the Register Method.
internal class Schedule<T> : IDisposable where T : ISchedule, new() {}
Here I get the following error:
'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Schedule<T>'
Is this behavior even possible or is there anything I am doing wrong?
You need to apply the where T : ISchedule, new() constraint you specified on the Schedule<T> class to the Register method as well:
public void Register<T>(TimeSpan interval, ILogger logger) where T : ISchedule, new()
{
_schedules.Add(new Schedule<T>(interval, logger));
}
Consider the following two classes which implement the ISchedule interface.
public class Schedule1 : ISchedule
{
public Schedule1() { }
}
public class Schedule2 : ISchedule
{
public Schedule2(string foo) { }
}
The Schedule<T> class has a generic type constraint where T : ISchedule, new() meaning only those types implementing ISchedule and containing a parameterless constructor can be used as the type parameter. Therefore, it is illegal to specify a Schedule<Schedule2> since Schedule2 does not contain a parameterless constructor.
If we do not apply the same type constraint to the Register method, we can call that method with both Schedule1 and Schedule2. As Schedule2 does not conform to Schedule<T>'s type constraint, we now have a problem ('T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'Schedule<T>') that can be solved by applying the same constraint of Schedule<T> to the Register method.
Further reading: Constraints on Type Parameters on Microsoft Docs.

Generic class and Constraint

I am working with Generic class and Constraint. Following is my class.
public class GenericList<T> where T : new()
{
private Node head;
// constructor
public GenericList()
{
head = null;
}
}
when i create object with integer it works fine
GenericList<int> list = new GenericList<int>();
But when i try with string it gives me following compile time error.
GenericList<string> list1 = new GenericList<string>();
'string' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'GenericTest.GenericList'
also when i passed reference parameter like any custom class it works fine.
What is the problem with string?
String Class does not have a public parameterless constructor..that is why the new() constraint is not applicable to it.
Read Constraints on Type Parameters (C# Programming Guide):
where T : new()
The type argument must have a public parameterless constructor. When
used together with other constraints, the new() constraint must be
specified last.
It is pointless for String type to have public parameterless constructor because String is immutable, which means that if String would have this constructor then it would have to create an empty string object and that is just stupid, because after creation you can not change it.

regarding the use of new Constraint in c#

i never use new Constraint because the use is not clear to me. here i found one sample but i just do not understand the use. here is the code
class ItemFactory<T> where T : new()
{
public T GetNewItem()
{
return new T();
}
}
public class ItemFactory2<T> where T : IComparable, new()
{
}
so anyone please make me understand the use of new Constraint with small & easy sample for real world use. thanks
This constraint requires that the generic type that is used is non-abstract and that it has a default (parameterless) constructor allowing you to call it.
Working example:
class ItemFactory<T> where T : new()
{
public T GetNewItem()
{
return new T();
}
}
which obviously now will force you to have a parameterless constructor for the type that is passed as generic argument:
var factory1 = new ItemFactory<Guid>(); // OK
var factory2 = new ItemFactory<FileInfo>(); // doesn't compile because FileInfo doesn't have a default constructor
var factory3 = new ItemFactory<Stream>(); // doesn't compile because Stream is an abstract class
Non-working example:
class ItemFactory<T>
{
public T GetNewItem()
{
return new T(); // error here => you cannot call the constructor because you don't know if T possess such constructor
}
}
In addition to Darin's answer, something like this would fail because Bar does not have a parameterless constructor
class ItemFactory<T> where T : new()
{
public T GetNewItem()
{
return new T();
}
}
class Foo : ItemFactory<Bar>
{
}
class Bar
{
public Bar(int a)
{
}
}
Actual error is: 'Bar' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'ItemFactory<T>'
The following would also fail:
class ItemFactory<T>
{
public T GetNewItem()
{
return new T();
}
}
Actual error is: Cannot create an instance of the variable type 'T' because it does not have the new() constraint
The new constraint specifies that any type argument in a generic class declaration must have a public parameterless constructor.
quoted from the official website
You can read new() as if it is an interface with a constructor. Just like that IComparable specifies that the type T has a method CompareTo, the new constraint specifies that the type T has a public constructor.
In your example, the constraint acts on <T> in the class declaration. In the first case, it requires that the generic T object has a default (parameterless) constructor. In the second example, it requires that T should have a default, parameterless constructor and that it must implement the IComparable interface.

Generic method compile time error

The following code:
private IList<T> DoStuff<T>()
{
IList<T> res = new List<T>();
for (int i = 0; i < 10; i++)
{
T item = DoOtherStuff<T>();
res.Add(item);
}
return res;
}
private T DoOtherStuff<T>() where T : new()
{
return new T();
}
Generates the following error:
'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'DoOtherStuff()'
Please may somebody explain why?
Change
private IList<T> DoStuff<T>()
to
private IList<T> DoStuff<T>() where T : new()
since otherwise you can't guarantee that T has a new() constructor.
Your DoOtherStuff<T> method has the where T : new() constraint. (That is, "T must be a non-abstract type with a public parameterless constructor".)
Your DoStuff<T> method doesn't have that constraint, which means that the compiler can't guarantee that all type arguments T that can legally be used for DoStuff will meet the where T : new() constraint required by DoOtherStuff.
DoOtherStuff's T specifies that T : new(), which means it has a public parameterless constructor. DoStuff's T has no restrictions, so you might not be able to say new T(). You should add where T : new() do DoStuff.

Create generic class with internal constructor

Is it possible to construct an object with its internal constructor within a generic method?
public abstract class FooBase { }
public class Foo : FooBase {
internal Foo() { }
}
public static class FooFactory {
public static TFooResult CreateFoo<TFooResult>()
where TFooResult : FooBase, new() {
return new TFooResult();
}
}
FooFactory resides in the same assembly as Foo. Classes call the factory method like this:
var foo = FooFactory.CreateFoo<Foo>();
They get the compile-time error:
'Foo' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'TFooType' in the generic type or method 'FooFactory.CreateFoo()'
Is there any way to get around this?
I also tried:
Activator.CreateInstance<TFooResult>();
This raises the same error at runtime.
You could remove the new() constraint and return:
//uses overload with non-public set to true
(TFooResult) Activator.CreateInstance(typeof(TFooResult), true);
although the client could do that too. This, however, is prone to runtime errors.
This is a hard problem to solve in a safe manner since the language does not permit an abstract constructor declaraton.
The type argument must have a
public parameterless constructor. When used together with other
constraints, the new() constraint must
be specified last.
http://msdn.microsoft.com/en-us/library/d5x73970.aspx
edit: so no, if you use new() constraint, you cannot pass that class, if you don't use new() constraint you can try using reflection to create new instance
public static TFooResult CreateFoo<TFooResult>()
where TFooResult : FooBase//, new()
{
return (TFooResult)typeof(TFooResult).GetConstructor(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] {}, null).Invoke(new object[]{});
//return new TFooResult();
}
There can be few work-arounds as below but I don't think you want to go that way!
Put switch statement inside Factory
that will create the instance based
on type of type parameter.
Each concrete implementation of FooBase will register with FooFactory passing the factory method to create it self. So FooFactory will use the internal dictionary
Extending on the similar line except mapping between type parameter and concrete implementation would be external code (xml file, configuration etc). IOC/DI containers can also help here.
public class GenericFactory
{
public static T Create<T>(object[] args)
{
var types = new Type[args.Length];
for (var i = 0; i < args.Length; i++)
types[i] = args[i].GetType();
return (T)typeof(T).GetConstructor(types).Invoke(args);
}
}

Categories