Passing arguments to C# generic new() of templated type
Asked Answered
I

17

484

I'm trying to create a new object of type T via its constructor when adding to the list.

I'm getting a compile error: The error message is:

'T': cannot provide arguments when creating an instance of a variable

But my classes do have a constructor argument! How can I make this work?

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T(listItem)); // error here.
   } 
   ...
}
Intertwine answered 8/5, 2009 at 15:4 Comment(4)
possible duplicate of Create instance of generic type?Meanly
Proposal to get this functionality into the language: github.com/dotnet/roslyn/issues/2206Craftwork
In Microsoft's documentation, see Compiler Error CS0417.Patricapatrice
Proposal to get this functionality into the language was moved to: github.com/dotnet/csharplang/issues/769Georgeannageorgeanne
S
450

In order to create an instance of a generic type in a function you must constrain it with the "new" flag.

public static string GetAllItems<T>(...) where T : new()

However that will only work when you want to call the constructor which has no parameters. Not the case here. Instead you'll have to provide another parameter which allows for the creation of object based on parameters. The easiest is a function.

public static string GetAllItems<T>(..., Func<ListItem,T> del) {
  ...
  List<T> tabListItems = new List<T>();
  foreach (ListItem listItem in listCollection) 
  {
    tabListItems.Add(del(listItem));
  }
  ...
}

You can then call it like so

GetAllItems<Foo>(..., l => new Foo(l));
Spiritualist answered 8/5, 2009 at 15:11 Comment(3)
How would this work when called internally from a generic class? I have posted my code in an answer below. I don't know the concrete class internally, as it's a generic class. Is there a way round this. I dont want to use the other suggestion of using property initialiser syntax as that will bypass the logic I have in the constructorTrunnion
added my code to another question #1682810Trunnion
Thanks. In my case I know the constructor's argument(s) when I call the method, I just needed to get around the Type parameter's limitation that it could not be constructed with parameters, so I used a thunk. The thunk is an optional parameter to the method, and I only use it if provided: T result = thunk == null ? new T() : thunk(); The benefit of this for me is consolidating the logic of T creation in one place rather than sometimes creating T inside and sometimes outside of the method.Loggerhead
O
377

in .Net 3.5 and after you could use the activator class:

(T)Activator.CreateInstance(typeof(T), args)
Olshausen answered 8/4, 2011 at 18:2 Comment(8)
we could also use expression tree to build the objectSmooth
What is args? an object[]?Aretta
Yes, args is an object[] where you specify the values to be provided to the T's constructor: "new object[]{ par1, par2 }"Aeri
If you can use "where T : SomeBaseClass", then you can maintain type safety when using an object[] by creating a "public static object[] GetArgs" method on SomeBaseClass with a list of parameters matching the constructor you want to use, then use the value returned from that as your "args" variable.Boardinghouse
Cautionary conclusion would be that Activator.CreateInstance<T> is taking roughly 11 times as much time to do the same job as a new T() does, and a delegate takes roughly 1.5 times as much. If you have a performance problem, first measure to see where your bottleneck is. Yes, the above timings might indicate that Activator.CreateInstance has more overhead than a dynamically built delegate, but there might be much bigger fish to fry in your codebase before you get (or even have to get) to this level of optimizationSchoolfellow
I found I had an error and needed to do this: Activator.CreateInstance(typeof(T), args) as TNoctambulous
@Noctambulous this only works for nullable types, so in a template the type T must contain some constraints. I can't imagine where the direct cast does not work, only in an error case if the object cannot be created.Olshausen
WARNING: If you have a dedicated constructor just for the sake of Activator.CreateInstance for this one thing, It will look like your constructor isn't used at all, and somebody might try to "clean up" and delete it (to cause a runtime error at some random time in the future). You may want to consider adding a dummy function where you use this constructor just so you get a compile error if you try to delete it.Reddy
R
53

Since nobody bothered to post the 'Reflection' answer (which I personally think is the best answer), here goes:

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       Type classType = typeof(T);
       ConstructorInfo classConstructor = classType.GetConstructor(new Type[] { listItem.GetType() });
       T classInstance = (T)classConstructor.Invoke(new object[] { listItem });

       tabListItems.Add(classInstance);
   } 
   ...
}

Edit: This answer is deprecated due to .NET 3.5's Activator.CreateInstance, however it is still useful in older .NET versions.

Rushy answered 16/6, 2010 at 15:39 Comment(4)
My understanding is that most of the performance hit is in acquiring the ConstructorInfo in the first place. Don't take my word for it without profiling it. If that is the case, simply storing the ConstructorInfo for later reuse could alleviate the performance hit of repeated instantiations through reflection.Throw
@James I agree, I was surprised not to see this as the "answer". In fact, I searched on this question expecting to find a nice easy example (like yours) since it's been so long since I've done reflection. Anyway, +1 from me, but +1 on the Activator answer too. I looked into what Activator is doing, and it turns out that what is does is some very well engineered reflection. :)Baldpate
The GetConstructor() call is expensive, so it is worth caching before the loop. This way, by calling only Invoke() inside the loop, it is a lot faster than calling both or even using Activator.CreateInstance().Incongruent
Performance concerns aside, this is not typesafe as everything is resolved at runtime. If the classType constructor changes, e.g. to become a list of IFoo rather than a list of concrete Foo, then the compiler won't give us any help at all. Things will continue to compile and you'll crash at runtimeLocomobile
D
38

Very old question, but new answer ;-)

The ExpressionTree version: (I think the fastests and cleanest solution)

Like Welly Tambunan said, "we could also use expression tree to build the object"

This will generate a 'constructor' (function) for the type/parameters given. It returns a delegate and accept the parameter types as an array of objects.

Here it is:

// this delegate is just, so you don't have to pass an object array. _(params)_
public delegate object ConstructorDelegate(params object[] args);

public static ConstructorDelegate CreateConstructor(Type type, params Type[] parameters)
{
    // Get the constructor info for these parameters
    var constructorInfo = type.GetConstructor(parameters);

    // define a object[] parameter
    var paramExpr = Expression.Parameter(typeof(Object[]));

    // To feed the constructor with the right parameters, we need to generate an array 
    // of parameters that will be read from the initialize object array argument.
    var constructorParameters = parameters.Select((paramType, index) =>
        // convert the object[index] to the right constructor parameter type.
        Expression.Convert(
            // read a value from the object[index]
            Expression.ArrayAccess(
                paramExpr,
                Expression.Constant(index)),
            paramType)).ToArray();

    // just call the constructor.
    var body = Expression.New(constructorInfo, constructorParameters);

    var constructor = Expression.Lambda<ConstructorDelegate>(body, paramExpr);
    return constructor.Compile();
}

Example MyClass:

public class MyClass
{
    public int TestInt { get; private set; }
    public string TestString { get; private set; }

    public MyClass(int testInt, string testString)
    {
        TestInt = testInt;
        TestString = testString;
    }
}

Usage:

// you should cache this 'constructor'
var myConstructor = CreateConstructor(typeof(MyClass), typeof(int), typeof(string));

// Call the `myConstructor` function to create a new instance.
var myObject = myConstructor(10, "test message");

enter image description here


Another example: passing the types as an array

var type = typeof(MyClass);
var args = new Type[] { typeof(int), typeof(string) };

// you should cache this 'constructor'
var myConstructor = CreateConstructor(type, args);

// Call the `myConstructor` fucntion to create a new instance.
var myObject = myConstructor(10, "test message");

DebugView of Expression

.Lambda #Lambda1<TestExpressionConstructor.MainWindow+ConstructorDelegate>(System.Object[] $var1) {
    .New TestExpressionConstructor.MainWindow+MyClass(
        (System.Int32)$var1[0],
        (System.String)$var1[1])
}

This is equivalent to the code that is generated:

public object myConstructor(object[] var1)
{
    return new MyClass(
        (System.Int32)var1[0],
        (System.String)var1[1]);
}

Small downside

All valuetypes parameters are boxed when they are passed like an object array.


Simple performance test:

private void TestActivator()
{
    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < 1024 * 1024 * 10; i++)
    {
        var myObject = Activator.CreateInstance(typeof(MyClass), 10, "test message");
    }
    sw.Stop();
    Trace.WriteLine("Activator: " + sw.Elapsed);
}

private void TestReflection()
{
    var constructorInfo = typeof(MyClass).GetConstructor(new[] { typeof(int), typeof(string) });

    Stopwatch sw = Stopwatch.StartNew();
    for (int i = 0; i < 1024 * 1024 * 10; i++)
    {
        var myObject = constructorInfo.Invoke(new object[] { 10, "test message" });
    }

    sw.Stop();
    Trace.WriteLine("Reflection: " + sw.Elapsed);
}

private void TestExpression()
{
    var myConstructor = CreateConstructor(typeof(MyClass), typeof(int), typeof(string));

    Stopwatch sw = Stopwatch.StartNew();

    for (int i = 0; i < 1024 * 1024 * 10; i++)
    {
        var myObject = myConstructor(10, "test message");
    }

    sw.Stop();
    Trace.WriteLine("Expression: " + sw.Elapsed);
}

TestActivator();
TestReflection();
TestExpression();

Results:

Activator: 00:00:13.8210732
Reflection: 00:00:05.2986945
Expression: 00:00:00.6681696

Using Expressions is +/- 8 times faster than Invoking the ConstructorInfo and +/- 20 times faster than using the Activator

Dallis answered 10/10, 2016 at 15:7 Comment(2)
Do you have any insight on what to do if you want to construct MyClass<T> with the constructor public MyClass(T data). In this case, Expression.Convert throws an exception and if I use the generic constraint base class to convert to, then Expression.New throws because the constructor info is for a generic typeLeoni
@Leoni (took a while to answer ;-)) var myConstructor = CreateConstructor(typeof(MyClass<int>), typeof(int)); this is working fine. I don't know.Dallis
E
34

Object initializer

If your constructor with the parameter isn't doing anything besides setting a property, you can do this in C# 3 or better using an object initializer rather than calling a constructor (which is impossible, as has been mentioned):

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T() { YourPropertyName = listItem } ); // Now using object initializer
   } 
   ...
}

Using this, you can always put any constructor logic in the default (empty) constructor, too.

Activator.CreateInstance()

Alternatively, you could call Activator.CreateInstance() like so:

public static string GetAllItems<T>(...) where T : new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
        object[] args = new object[] { listItem };
        tabListItems.Add((T)Activator.CreateInstance(typeof(T), args)); // Now using Activator.CreateInstance
   } 
   ...
}

Note that Activator.CreateInstance can have some performance overhead that you may want to avoid if execution speed is a top priority and another option is maintainable to you.

Exam answered 22/2, 2012 at 20:39 Comment(2)
this prevents T from protecting it's invariants (given that T has >0 dependencies or required values, you can now create instances of T that are in an invalid/unusable state. unless T is something dead simple like a DTO och viewmodel, I'd say avoid this.Floozy
This also requires properties not being encapsulated.Guertin
F
20

This will not work in your situation. You can only specify the constraint that it has an empty constructor:

public static string GetAllItems<T>(...) where T: new()

What you could do is use property injection by defining this interface:

public interface ITakesAListItem
{
   ListItem Item { set; }
}

Then you could alter your method to be this:

public static string GetAllItems<T>(...) where T : ITakesAListItem, new()
{
   ...
   List<T> tabListItems = new List<T>();
   foreach (ListItem listItem in listCollection) 
   {
       tabListItems.Add(new T() { Item = listItem });
   } 
   ...
}

The other alternative is the Func method described by JaredPar.

Francisco answered 8/5, 2009 at 15:13 Comment(2)
this would bypass any logic that is in the constructor that takes the arguments though, right? I would like to do something Like Jared's approach but am calling the method internally within the class so don't know what the concrete type is...hmmmTrunnion
Right, this calls the logic of the T() default constructor, then simply sets the property "Item". If you're trying to invoke the logic of a non-default constructor, this will not help you.Finalism
A
7

You need to add where T: new() to let the compiler know that T is guaranteed to provide a default constructor.

public static string GetAllItems<T>(...) where T: new()
Audwin answered 8/5, 2009 at 15:6 Comment(6)
UPDATE: The correct error message is: 'T': cannot provide arguments when creating an instance of a variableIntertwine
That's because you're not using a blank constructor, you're passing an argument to it of object. There's no way it can handle that without specifying that the generic Type has a new(object) parameter.Madid
Then you'll need to either: 1. Use reflection 2. Pass the parameter into an initialization method instead of the constructor, where the initialization method belongs to an interface that your type implements and which is included in the where T: ... declaration. Option 1 is the lowest impact for the rest of your code, but option 2 provides compile time checking.Audwin
Don't use reflection! There are other ways as outlined in other answers that get you the same effect.Francisco
@Garry - I'd agree that reflection isn't necessarily the best approach, but it does allow you to achieve what's required with minimal change to the rest of the code base. That said, I do much prefer the factory delegate approach from @JaredPar.Audwin
If really need pass parameter then use reflection, if you aren't then use @richards example. eg. CurrentDataStore[UnitOfWorkDataStore.DATA_CONTEXT_KEY] = new T(); works perfectly. to create a new EF dataContextTantara
T
7

If you simply want to initialise a member field or property with the constructor parameter, in C# >= 3 you can do it very easier:

public static string GetAllItems<T>(...) where T : InterfaceOrBaseClass, new() 
{ 
   ... 
   List<T> tabListItems = new List<T>(); 
   foreach (ListItem listItem in listCollection)  
   { 
       tabListItems.Add(new T{ BaseMemberItem = listItem }); // No error, BaseMemberItem owns to InterfaceOrBaseClass. 
   }  
   ... 
} 

This is the same thing Garry Shutler said, but I'd like to put an aditional note.

Of course you can use a property trick to do more stuff than just setting a field value. A property "set()" can trigger any processing needed to setup its related fields and any other need for the object itself, including a check to see if a full initialization is to take place before the object is used, simulating a full contruction (yes, it is an ugly workaround, but it overcomes M$'s new() limitation).

I can't be assure if it is a planned hole or an accidental side effect, but it works.

It is very funny how MS people adds new features to the language and seems to not do a full side effects analysis. The entire generic thing is a good evidence of this...

Tiepolo answered 30/4, 2010 at 17:45 Comment(1)
Both constraints are needed. InterfaceOrBaseClass makes the compiler aware of the field/property BaseMemberItem. If the "new()" constraint is commented, it will trigger the error: Error 6 Cannot create an instance of the variable type 'T' because it does not have the new() constraintTiepolo
N
7

I found that I was getting an error "cannot provide arguments when creating an instance of type parameter T" so I needed to do this:

var x = Activator.CreateInstance(typeof(T), args) as T;
Noctambulous answered 6/11, 2015 at 11:13 Comment(0)
N
7

If you have access to the class you're going to use, you can use this approach which I used.

Create an interface that has an alternative creator:

public interface ICreatable1Param
{
    void PopulateInstance(object Param);
}

Make your classes with an empty creator and implement this method:

public class MyClass : ICreatable1Param
{
    public MyClass() { //do something or nothing }
    public void PopulateInstance (object Param)
    {
        //populate the class here
    }
}

Now use your generic methods:

public void MyMethod<T>(...) where T : ICreatable1Param, new()
{
    //do stuff
    T newT = new T();
    T.PopulateInstance(Param);
}

If you don't have access, wrap the target class:

public class MyClass : ICreatable1Param
{
    public WrappedClass WrappedInstance {get; private set; }
    public MyClass() { //do something or nothing }
    public void PopulateInstance (object Param)
    {
        WrappedInstance = new WrappedClass(Param);
    }
}
Noach answered 13/7, 2017 at 15:4 Comment(0)
E
4

Using the static abstract interface methods feature in C# 11 it is possible to build a workaround, using a factory pattern. For example:

public interface IFactory<TSelf> where TSelf : IFactory<TSelf> {
  static abstract TSelf New(int i, string s);
}

public struct Foo : IFactory<Foo> {

  public static Foo New(int i, string s) {
    return new Foo(i, s);
  }

  public readonly int I;
  public readonly string S;

  public Foo(int i, string s) {
    I = i;
    S = s;
  }
}

public static class Maker {
  public static T Make<T>(int i, string s) where T : IFactory<T> {
    return T.New(i, s);
  }
}

A limitation of this approach is that it can only be used on classes that you own, since you need to implement your specific factory interface on the target classes.

Ermentrude answered 11/11, 2022 at 11:9 Comment(0)
F
0

This is kind of mucky, and when I say kind of mucky I may mean revolting, but supposing you can furnish your parameterised type with an empty constructor, then:

public static T GetTInstance<T>() where T: new()
{
    var constructorTypeSignature = new Type[] {typeof (object)};
    var constructorParameters = new object[] {"Create a T"};
    return (T) new T().GetType().GetConstructor(constructorTypeSignature).Invoke(constructorParameters);
}

Will effectively allow you to construct an object from a parameterised type with an argument. In this case I am assuming the constructor I want has a single argument of type object. We create a dummy instance of T using the constraint permitted empty constructor and then use reflection to get one of its other constructors.

Fosdick answered 12/11, 2010 at 11:38 Comment(0)
E
0

I sometimes use an approach that resembles to the answers using property injection, but keeps the code cleaner. Instead of having a base class/interface with a set of properties, it only contains a (virtual) Initialize()-method that acts as a "poor man's constructor". Then you can let each class handle it's own initialization just as a constructor would, which also adds a convinient way of handling inheritance chains.

If often find myself in situations where I want each class in the chain to initialize its unique properties, and then call its parent's Initialize()-method which in turn initializes the parent's unique properties and so forth. This is especially useful when having different classes, but with a similar hierarchy, for example business objects that are mapped to/from DTO:s.

Example that uses a common Dictionary for initialization:

void Main()
{
    var values = new Dictionary<string, int> { { "BaseValue", 1 }, { "DerivedValue", 2 } };

    Console.WriteLine(CreateObject<Base>(values).ToString());

    Console.WriteLine(CreateObject<Derived>(values).ToString());
}

public T CreateObject<T>(IDictionary<string, int> values)
    where T : Base, new()
{
    var obj = new T();
    obj.Initialize(values);
    return obj;
}

public class Base
{
    public int BaseValue { get; set; }

    public virtual void Initialize(IDictionary<string, int> values)
    {
        BaseValue = values["BaseValue"];
    }

    public override string ToString()
    {
        return "BaseValue = " + BaseValue;
    }
}

public class Derived : Base
{
    public int DerivedValue { get; set; }

    public override void Initialize(IDictionary<string, int> values)
    {
        base.Initialize(values);
        DerivedValue = values["DerivedValue"];
    }

    public override string ToString()
    {       
        return base.ToString() + ", DerivedValue = " + DerivedValue;
    }
}
Eastlake answered 30/1, 2017 at 13:53 Comment(0)
C
0

If all is you need is convertion from ListItem to your type T you can implement this convertion in T class as conversion operator.

public class T
{
    public static implicit operator T(ListItem listItem) => /* ... */;
}

public static string GetAllItems(...)
{
    ...
    List<T> tabListItems = new List<T>();
    foreach (ListItem listItem in listCollection) 
    {
        tabListItems.Add(listItem);
    } 
    ...
}
Concerned answered 1/10, 2019 at 10:20 Comment(0)
P
0

Just to expand on the Expression tree answer a little bit. If you want to avoid param list and typed delegates, you can use generics and plain old static classes to cache all of your expressions.

The first usage of a type and/or arguments does takes more time, because of compiling, but afterwards the speed is unmatched.

public static class New<T>
{
    private readonly static Type TypeOfT = typeof(T);
    public static T Create()
    {
        return Build.Instantiate();
    }
    public static T Create<Arg1>(Arg1 arg1)
    {
        return Build<Arg1>.Instantiate(arg1);
    }

    public static T Create<Arg1, Arg2>(Arg1 arg1, Arg2 arg2)
    {
        return Build<Arg1, Arg2>.Instantiate(arg1, arg2);
    }

    public static Func<T> Construct()
    {
        return Build.Constructor;
    }

    public static Func<Arg1, T> Construct<Arg1>()
    {
        return Build<Arg1>.Constructor;
    }

    public static Func<Arg1, Arg2, T> Construct<Arg1, Arg2>()
    {
        return Build<Arg1, Arg2>.Constructor;
    }

    private static class Helper
    {
        public static Tuple<NewExpression, ParameterExpression[]> CreateExpressions(Type[] argsTypes)
        {
            var constructorInfo = TypeOfT.GetConstructor(argsTypes);
            var constructorParameters = argsTypes.Select(p => Expression.Parameter(p)).ToArray();
            var expression = Expression.New(constructorInfo, constructorParameters);
            return new Tuple<NewExpression, ParameterExpression[]>(expression, constructorParameters);
        }
    }

    private static class Build
    {
        public static readonly Func<T> Constructor = Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile();
        public static T Instantiate() => Constructor.Invoke();
    }

    private static class Build<Arg1>
    {
        public static readonly Func<Arg1, T> Constructor = CreateConstructor();
        public static T Instantiate(Arg1 arg) => Constructor.Invoke(arg);
        private static Func<Arg1, T> CreateConstructor()
        {
            var expressionAndParam = Helper.CreateExpressions(new Type[] { typeof(Arg1) });
            return Expression.Lambda<Func<Arg1, T>>(expressionAndParam.Item1, expressionAndParam.Item2).Compile();
        }
    }

    private static class Build<Arg1, Arg2>
    {
        public static Func<Arg1, Arg2, T> Constructor = CreateConstructor();
        public static T Instantiate(Arg1 arg1, Arg2 arg2) => Constructor.Invoke(arg1, arg2);
        private static Func<Arg1, Arg2, T> CreateConstructor()
        {
            var expressionAndParam = Helper.CreateExpressions(new Type[] { typeof(Arg1), typeof(Arg2) });
            return Expression.Lambda<Func<Arg1, Arg2, T>>(expressionAndParam.Item1, expressionAndParam.Item2).Compile();
        }
    // removed the rest of the code for brevity but you
    // would use the same pattern to continue with as many 
    // expected arguments as you may need
}

Example of usage.

// create the list with initial capacity
var list = New<List<string>>.Create(10);
        
// constructor for int as a Func
Func<int> integerConstructor = New<int>.Construct();
int x = integerConstructor.Invoke();

MyClass myclass = New<MyClass>.Create("hello", "world");
Pecan answered 29/11, 2023 at 4:59 Comment(0)
Q
-1

Supplementary performance information

Performance test of database access and filling of data model class with the expression method of Jeroen van Langen (see above) and direct instantiation of the data model class.

Conclusion: The expression method is faster.

Results:

  1. Test: direct instance of data model class: Records: 3558, seconds: 1.2746019
  2. Test: instance with method read list with type parameter: records: 3558, seconds: 0.4878858

Code example of the expression method:

var list = ReadList<DataModel>(SQLStatement, Connection);

Method ReadList: Note: all data model class has a constructor with parameter type of SQLDataReader

public static List<pDataModel> ReadList<pDataModel>(string pSQLStatement, SqlConnection pConnection) where pDataModel : new()
    {
            // constructor of data model
            var lType = typeof(pDataModel);
            var lParameters = new Type[] { typeof(SqlDataReader) };
            var lDataModelConstructor = CreateConstructor(lType, lParameters);

            // read data
            List<pDataModel> lDataList = new List<pDataModel>();
            using (pConnection)
            {
                SqlCommand lCommand;
                lCommand = new SqlCommand(pSQLStatement, pConnection);
                pConnection.Open();
                SqlDataReader lReader = lCommand.ExecuteReader();


                if (lReader.HasRows)
                {
                    while (lReader.Read())
                    {
                        pDataModel lDataItem = (pDataModel)lDataModelConstructor(lReader);
                        lDataList.Add(lDataItem);
                    }
                }
                lReader.Close();
                pConnection.Close();
            }

            return lDataList;
    }

Code example of the direct instantiation:

           List<DataModel> list= new List<DataModel>();
            using (connection)
            {
                SqlCommand command;
                command = new SqlCommand(SQLStatement, connection);
                connection.Open();
                SqlDataReader reader = command.ExecuteReader();
                if (reader.HasRows)
                {
                    while (reader.Read())
                    {
                        list.Add(new DataModel(reader));
                    }
                }
                reader.Close();
                connection.Close();
            }
Quintonquintuple answered 1/8, 2021 at 18:49 Comment(0)
C
-3

I believe you have to constraint T with a where statement to only allow objects with a new constructor.

RIght now it accepts anything including objects without it.

Chancey answered 8/5, 2009 at 15:8 Comment(1)
You may want to change this answer because this got edited into the question after you answered which leaves this answer out of context.Carruthers

© 2022 - 2024 — McMap. All rights reserved.