C# generics creating new instances - c#

I'm attempting to write a generic method based on the following myMethod:
void myMethod(myClassA instanceA, myClassB instanceB)
{
instanceA = new myClassA(instanceB);
}
What I've got so far is something like this (myMethod_new), which has some errors:
void myMethod_new<S, T>(S instanceA, T instanceB) where S : new()
{
instanceA = new S(instanceB);
}
However, since I've not mastered how generics work in C#, how should this be implemented?

You can't create a new instance of a generic type if the type has parameters in the constructor. From the docs (emphasis mine):
The new constraint specifies that a type argument in a generic class declaration must have a public parameterless constructor.
One option is to use Activator.CreateInstance and pass in the parameter(s) required. However, that can lead to runtime exceptions since the caller could pass in any type with any format of constructor.
My advice would be to refactor slightly by removing the constructor parameter and create a method to pass that value in, then use an interface to contstrain it all. For example:
// The interface
public interface IHasThing<T>
{
void SetThing(T value);
}
// An implementation of the interface
public class Foo : IHasThing<string>
{
private string _value;
public void SetThing(string value)
{
_value = value;
}
}
And your updated method that returns the new object:
public S myMethod_new<S, T>(T instanceB) where S : IHasThing<T>, new()
{
var s = new S();
s.SetThing(instanceB);
return s;
}
So now you can call the method like this:
var foo = myMethod_new<Foo, string>("bar");

Related

Why my convarian (out keyword) not working?

How to use the Covariance(out keyword)?I have no idea.
I know out keyword in Interface mean Covariance that allow you use a more derived type than that specified by the generic parameter.
So i set generic to object and return type to string.Because string is subclass of object.
But i tried and it not working.
public interface IMyInterface<out T>
{
public T Foo();
}
public class CovarianceTest : IMyInterface<object>
{
public string Foo()
{
return "abc";
}
}
Covariance that allow you use a more derived type than that specified by the generic parameter
That's not what it means. You still have to write methods that match the types in the interface. So you will have to do this:
public class CovarianceTest : IMyInterface<string>
{
public string Foo()
{
return "abc";
}
}
What covariance allow you to do is assign the class instance to a variable typed as a less specific interface, like this:
IMyInterface<object> x = new CovarianceTest();
Console.WriteLine(x.Foo());
That's because all Ts read from the interface (i.e. taken out) are guaranteed to be instances that are type-compatible with the less specific type, i.e. all strings are also objects.
I suspect you are trying to do the following.
public interface IMyInterface<out T>
{
public T Foo();
}
public class CovarianceTest : IMyInterface<string>
{
public string Foo()
{
return "abc";
}
}
IMyInterface<string> works = new CovarianceTest();
IMyInterface<object> alsoWorks = new CovarianceTest();
IMyInterface<int> doesNotWork = new CovarianceTest();

Is there a way to specify a generic type parameter as having a constructor that accepts a string? [duplicate]

I have a wrapper generic class that intended to be used with a set of types. Those types are generated by a utility and are all derived from a base class ClientBase. While ClientBase has only a default constructor, all generated types have default constructor as well as a constructor takes a string as parameter. In the constructor of the wrapper class, I instantiate an instance of the type with the constructor that takes a string. Here is a sample code:
public class ClientBase
{ }
public class GenericProxy<T>
where T: ClientBase, new()
{
T _proxy;
public GenericProxy(string configName)
{
_proxy = new T(configName);
}
}
This code does not compile because type T is not guaranteed to have a constructor that takes a string. Is there a way to define a constrain on the generic class to enforce that the type T must have a constructor that take a string? If this is not possible, what are good alternatives to handle this kind of situation?
It's not possible. I'd like to see "static interfaces" to handle this, but don't expect them any time soon...
Alternatives:
Specify a delegate to act as a factory for T
Specify another interface to act as a factory for T
Specify an interface on T itself for initialization (and add a constraint so that T implements the interface)
The first two are really equivalent. Basically you'd change your proxy class to something like this:
public class GenericProxy<T>
where T: ClientBase, new()
{
string _configName;
T _proxy;
Func<string, T> _factory;
public GenericProxy(Func<string, T> factory, string configName)
{
_configName = configName;
_factory = factory;
RefreshProxy();
}
void RefreshProxy() // As an example; suppose we need to do this later too
{
_proxy = _factory(_configName);
}
}
(I assume you're going to want to create more instances later - otherwise you might as well pass an instance of T into the constructor.)
Unfortunately what you're trying to do isn't possible.
MSDN article on Type Constraints
This does not answer your actual question, constraining a method, but for completeness here's how you can do what you're asking at run time, using reflection:
private T Get<T>(string id)
{
var constructor = typeof(T).GetConstructor(new Type[] { typeof(X), typeof(Y) });
if (constructor == null) throw new InvalidOperationException("The type submitted, " + typeof(T).Name + ", does not support the expected constructor (X, Y).");
var data = GetData(id);
return (T)constructor.Invoke(new object[] { data.x, data.y });
}
As Jon notes, there is no inbuilt support for this - but as an aside you can create a typed delegate to the constructor (faster than reflection) using Expression. The code to do this can be found in MiscUtil (in MiscUtil.Linq.Extensions.TypeExt).
Here is a full working example based on #JonSkeet answer:
using System;
using System.Collections.Generic;
namespace GenericProxy
{
class Program
{
static void Main()
{
GenericProxy<ClientBase> proxy = new GenericProxy<ClientBase>(ClientBase.Factory, "cream");
Console.WriteLine(proxy.Proxy.ConfigName); // test to see it working
}
}
public class ClientBase
{
static public ClientBase Factory(string configName)
{
return new ClientBase(configName);
}
// default constructor as required by new() constraint
public ClientBase() { }
// constructor that takes arguments
public ClientBase(string configName) { _configName = configName; }
// simple method to demonstrate working example
public string ConfigName
{
get { return "ice " + _configName; }
}
private string _configName;
}
public class GenericProxy<T>
where T : ClientBase, new()
{
public GenericProxy(Func<string, T> factory, string configName)
{
Proxy = factory(configName);
}
public T Proxy { get; private set; }
}
}
Expect to see the following output: ice cream

C# Method Overloading - Parameter type overloads with derived types

What are the rules by which C# determines which overload of a constructor (or method) is to be used under the following circumstances:
Overloads differ only by the type of the parameter
The overloads are all part of the same type hierarchy
Consider the following:
A custom type derived from List (only a partial representation here; let's say for the sake of the exercise that the class adds some notion of metadata to List):
public class CustomList<Type> : List<Type>
{
public CustomList() : base() { }
[...]
}
A class with different constructors taking different levels of the class hierarchy:
public class SomeClass
{
public SomeClass(IEnumerable<object> ienumerable) { }
public SomeClass(IList<object> list) { }
public SomeClass(CustomList<object> customList) { }
}
Which constructor will be called in the following code, and how are the overloads resolved?:
CustomList<object> customList = new CustomList<object>();
List<object> list = new List<object>();
IEnumerable<object> enumerable = new object[1];
IEnumerable<object> customListWrappedInEnumerable = new CustomList<object>();
SomeClass customListBuilt = new SomeClass(customList);
SomeClass listBuilt = new SomeClass(list);
SomeClass enumerableBuilt = new SomeClass(enumerable);
SomeClass wrappedCustomListBuilt = new SomeClass(customListWrappedInEnumerable);
As a secondary question, are the overloading rules the same for constructors as for other instance methods? If I have this class:
public static class DoSomethingClass
{
public void DoSomething(IEnumerable<object> ienumerable) { }
public void DoSomething(IList<object> list) { }
public void DoSomething(CustomList<object> customList) { }
}
And I call
DoSomethingClass.DoSomething(list);
DoSomethingClass.DoSomething(customList);
DoSomethingClass.DoSomething(enumerable);
DoSomethingClass.DoSomething(customListWrappedInEnumerable);
is the behavior the same or different than the constructor? And further, if DoSomethingClass were an instance type instead, would
DoSomethingClass do = new DoSomethingClass();
do.DoSomething(customListWrappedInEnumerable);
[...]
be any different?
My observation so far has been that the type of the reference passed to the constructor/method entirely determines which constructor is chosen. i.e. the CustomList wrapped in an IEnumerable overloads to the IEnumerable constructor. Would I be correct in assuming that is always the case, or are their exceptions?

Constructor with optional parameter violates new() constraint

I have a class with this constructor:
public Currency(Guid? vcurrencyUI = null)
: base(vcurrencyUI)
{ }
and I want to use this class with a new() constraint but I get this error:
'Currency' 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 ...
If I split the constructor everything works fine:
public Currency(Guid? vcurrencyUI)
: base(vcurrencyUI)
{ }
public Currency()
: base()
{ }
why do I need to split the constructor?
Because a constructor with a default parameter is not a parameterless constructor.
Default parameters are "filled in" by the compiler at compile time. When you write:
var foo = new Currency();
The compiler generates:
var foo = new Currency(null);
When the class is compiled, the compiler creates a constructor that takes that Guid? parameter, and also generates some metadata that says in effect "if the parameter isn't supplied at compile time, then supply null." But no parameterless constructor is generated for the type.
The new() constraint requires that a parameterless constructor be defined for the type, and it won't accept a constructor with a single default parameter. Most likely that's because the runtime, which ends up having to call the constructor, doesn't understand the concept of default parameters.
Although Jim already answered your question, note that a more general approach might be to allow passing a delegate which would instantiate your concrete class, instead of forcing all your implementations to be parameterless.
I.e. instead of this:
public class Something<T> where T : new()
{
public T CreateInstance()
{
return new T();
}
}
You can pass an explicit delegate which will do any custom instantiation logic:
// note that the constraint is now removed
public class Something<T>
{
private readonly Func<T> _ctor;
public Something(Func<T> ctor)
{
_ctor = ctor;
}
public T CreateInstance()
{
return _ctor();
}
}
// and you can now pass arbitrary constructor logic as a delegate
var x = new Something<Currency>( () => new Currency(null) );
This also allows you to create a helper class and have both options readily available:
public class Something
{
// this allows you to use a parameterless ctor
public static Something<T> Create<T>() where T : new()
{
return new Something<T>(() => new T());
}
// this allows you to specify a custom one
public static Something<T> Create<T>(Func<T> ctor)
{
return new Something<T>(ctor);
}
}

Cast generic class to interface

I have a problem with casting a generic class to the interface it is implementing.
My code is like this:
interface foo
{
void foobar();
}
class bar: foo
{
public void foobar()
{
throw new NotImplementedException();
}
}
now I have my factory that creates instances of my classes by the interface, mostly a simple microkernel (service locator). I will simplify it here. Normally it will look up the implementing class from the configs and the factory take the type as T but that doesn't matter for the problem I have.
public static class Factory
{
public static Lazy<foo> CreateLazyInstance()
{
Lazy<foo> instance;
Type type = typeof(bar);
Type lazyType = typeof(Lazy<>);
Type toContruct = lazyType.MakeGenericType(type);
instance = (Lazy<foo>)Activator.CreateInstance(toContruct);
return instance;
}
}
If will fail at:
instance = (Lazy<foo>)Activator.CreateInstance(toContruct);
and claim with an InvalidCastException that it is not possible to cast the type Lazy<bar> to Lazy<foo>.
Is there any way to tell the CLR that this cast will work or to workaround this problem?
No - Lazy<T> is invariant - so a Lazy<string> is not a Lazy<object> for example. (As pointed out in comments, it couldn't be declared as covariant in T, as it's a class, not an interface or delegate.)
However, you can convert one to the other easily enough:
static Lazy<TOutput> CreateLazyProxy<TInput, TOutput>
(Lazy<TInput> input) where TInput : TOutput
{
return new Lazy<TOutput>(() => input.Value);
}
Also, Func<T> is covariant, so this will work too:
static Lazy<TOutput> CreateLazy<TInput, TOutput>(Func<TInput> func)
where TInput : TOutput
{
return new Lazy<TOutput>(func);
}
(Not that you particularly need a method for that - if you've got a Func<TInput>, just construct a Lazy<TOutput> directly.)
An easier way to do this would be to pass in a lambda to the Lazy constructor. So, your code would look like the following:
public static Lazy<foo> CreateLazyInstance()
{
Type type = typeof(bar);
return new Lazy<foo>(() => (foo)Activator.CreateInstance(type));
}
You must do your foo generic parameter : new():
public static Lazy<foo> CreateLazyInstance() where foo : new()
And change your code to find a constructor and call it:
Type t = typeof(foo);
t.GetConstructor(new type[]{});
return (foo)t.Invoke(new object[]{});

Categories

Resources