Generics with runtime Types - c#

I am using Moq and want to mock an interface which inherits from ICloneable. I am using Newtonsoft.Json to serialise and deserialise my object to a cloned instance.
The interface:
public interface ITestInterface : ICloneable
{
int Number { get; set; }
string Text { get; set; }
string MethodCallResult { get; set; }
void CallMe();
}
I am trying to use generics to convert the object but I cannot know the actual runtime type of the proxy which Moq will provide.
Using the debugger through the following method I can see that the runtime type is a proxy but the type of the generic 'T' is the interface, ITestInterface, which cannot be serialised. How can I use the real runtime type with generics to serialize/deserialize these objects? I would just pass the type as a parameter but I do not know it at compile time.
private object CreateClone<T>(T item)
where T : class
{
var realRuntimeType = item.GetType(); //is a proxy created by Moq inheriting from the interface
var itemAsSerializedString = JsonConvert.SerializeObject( item );
return JsonConvert.DeserializeObject<T>( itemAsSerializedString ); //wont work, tries to instantiate interface
}
Usage (note that the generic parameter is inferred, not explicit):
var mock = new Mock<ITestInterface>();
mock.Setup(m => m.Clone()).Returns(CreateClone(mock.Object));
Exception:
Newtonsoft.Json.JsonSerializationException : Could not create an instance of type Processus.Tests.ITestInterface. Type is an interface or abstract class and cannot be instantiated.

Related

How to convert object to specific class with using type information

I have a interface. That interface name is IQueue. Also I have concrete classes. Their names are MyMessage1 and MyMessage2.
public interface IQueue
{
}
public class MyMessage1 : IQueue
{
public string Message { get; set; }
public DateTime PublishedDate { get; set; }
}
public class MyMessage2 : IQueue
{
public string Name { get; set; }
}
I am getting all the concrete classes implemented from IQueue with reflection and create a instance.
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => typeof(IQueue).IsAssignableFrom(p) && p.IsClass)
.ToList);
foreach(var type in types)
{
var instance = Activator.CreateInstance(type);
}
Instance is an object. How I can cast to specific class without using below code? Is it possible.
(MyMessage1)Activator.CreateInstance(type)
(MyMessage2)Activator.CreateInstance(type)
I want to create a specific class instance using type information
Cast to the type IQueue since all the types you want to instantiate implement that interface.
IQueue instance = (IQueue)Activator.CreateInstance(type);
Add methods and properties you want to use to that interface. The concrete classes will then have to implement these methods and properties and you can access them via the interface.

Polymorphic base class with non-polymorphic child classes and abstraction

Consider I have a TemplateEngine with the three classes:
TemplateEngine
TemplateBase<T> where T : TemplateDataBase
TemplateDataBase
and the sample implementation:
SampleTemplate : TemplateBase<SampleTemplateData>
SampleTemplateData : TemplateDataBase
and now, in the engine, a getter function:
public T GetTemplate<T, U>() where T: TemplateBase<U>, new() where U : TemplateDataBase
{
var template = new T();
...
return template;
}
Since all implementations of TemplateBase will have exactly one valid value for U, like the sample, the type of U can be infered through the choice of T, and I shouldn't have to provide it to the GetTemplate method.
Other TemplateData classes contain completely different data and one shouldn't be able to use the wrong TemplateData class for a certain template.
If I now remove the U type parameter from the function call, I get "Incorrect number of type parameters", or, if I remove it from the function definition, the getter is no longer valid because "Cannot resolve U".
If I keep the parameter, I still am not allowed to do so because "There is no implicit reference conversion from SampleTemplate to TemplateBase<TemplateDataBase>".
What am I doing wrong here?
Since you are trying to use a type parameter that is a child of the type parameter defined in the GetTemplate method, you'll need to use a covariant type parameter. Which by definition
Enables you to use a more derived type than originally specified
And since variance modifies can only be applied to interfaces or delegates, you'll need to create one of the two. Here's an example of using a generic interface with a covariant type parameter that allows you the type parameter to be implied:
interface ITemplate<out T> where T : TemplateDataBase
{
Type DataType { get; }
}
class TemplateBase<T> : ITemplate<T> where T : TemplateDataBase
{
public Type DataType => typeof(T);
}
class TemplateDataBase { }
class TemplateEngine
{
public T GetTemplate<T>() where T : ITemplate<TemplateDataBase>, new()
{
var template = new T();
return template;
}
}
class SampleTemplate : TemplateBase<SampleTemplateData> { }
class SampleTemplateData : TemplateDataBase { }
Note the ITemplate<out T>. This is what actually says that the type parameter is covariant.
And here's an example of the use site where the type is being inferred:
static void Main(string[] args)
{
var engine = new TemplateEngine();
var sampleTemplate = engine.GetTemplate<SampleTemplate>();
Console.WriteLine($"{sampleTemplate.DataType.Name}");
Console.ReadLine();
}

Using generics in interfaces in C#

I have an app written in C#. My app has a class that looks like the following:
public class FinderA
{
public IEnumerable<FinderA> GetItems()
{
return FinderA.FindAll();
}
}
I want to require other classes to do something similar. I cannot use a base class because my actual implementation is already using a base class. For that reason, I want to create an interface. Currently, I'm trying the following:
public interface IFinder
{
IEnumerable<T> GetItems();
}
When I use this approach, I get a compile-time error that says: "The type or namespace name 'T' could not be found (are you missing...". To overcome this, I add <T> to the end of the interface name so it looks like this:
public interface IFinder<T>
{
IEnumerable<T> GetItems();
}
This is turn generates another compile-time error that says: "Using the generic type 'IFinder' requires 1 type arguments.". My challenge is, I want the interface to be generic. I do not want to pass in a type. Is there a way around this? If so, what/how?
There is no way around this; you'll need to actually supply the generic type argument when declaring that a class implements the interface.
You can do this at the method level instead of as a generic type on the interface itself.
public interface IFinder
{
IEnumerable<T> GetItems<T>();
}
Your code can then call it like such:
IFinder finder = // Create finder instance
IEnumerable<MyClass> discoveredClasses = finder.GetItems<MyClass>();
If you want to ensure that MyClass is a class that implements IFinder, you can constrain the method.
public interface IFinder
{
IEnumerable<T> GetItems<T>() where T : IFinder;
}
That will cause the following to generate a compiler error:
public class Foo
{
}
public class Bar
{
Bar()
{
IFinder finder = // Create finder.
// This fails because <T> (Foo) does not implement IFinder.
IEnumerable<Foo> fooItems = finder.GetItems<Foo>();
}
}
but it will allow the following to compile
public class MyFinderA : IFinder
{
IEnumerable<T> GetItems<T>() where T : IFinder
{
return // Create collection of T
}
public class Bar
{
Bar()
{
IFinder finder = // Create finder.
// This works as <T> (MyFinderA) is an IFinder implementation
IEnumerable<MyFinderA> finderItems = finder.GetItems<MyFinderA>();
}
}
If you want your interface to be generic but you are not willing to supply a type argument, you can return an IEnumerable<object>.
public interface IFinder {
IEnumerable<object> GetItems();
}
All class types extend from System.Object so that should suffice for any type in your applicacion (enums and structs would get boxed)
Please note that this approach requires the interface's consumer to cast the generic object instances to the appropiate types.
The alternate (and recommended) approach is to make the interface use type parameters, but for that you must supply the appropiate type arguments

Reading concrete class property within a generic method that doesn't get generic type instance

Suppose I have a generic method that is made generic just for the purpose of returning correct type so upstream callers don't have to cast returned values.
public T Add<T>(string name, string details, ...)
where T: BaseClass
{
// somehow get correct ObjectType
ObjectType type = ??????;
T result = Repo.Add<T>(type, name, details, ...);
...
return result;
}
Problem
The problem of this generic method is that I'm not getting an instance of a concrete class represented with generic type. This means that callers of this method have to explicitly provide generic type as type inference can't be done.
public abstract class BaseClass
{
public abstract ObjectType ActualType { get; }
...
}
Implemented child classes define this property as a quasy constant
public class ConcreteClass: BaseClass
{
public override ObjectType ActualType
{
get { return ObjectType.SomeType; }
}
...
}
Question
Based on generic method call
var result = Add<ConcreteClass>("title", "details");
how can I get the value of ActualType within my Add<T> method? I also tried adding new() generic type constraint, but that doesn't compile as my BaseClass is abstract, so I'm unable to call
new T();
within my method to get that ActualType value.
You need to apply the new() constraint to your Add method like this:
public T Add<T>(string name, string details)
where T: BaseClass, new()
{
T result = new T();
//snip
return result;
}
public abstract class BaseClass { /* snip */ }
public class ConcreteClass: BaseClass { /* snip */ }
Which means this code will work:
var thing = Add<ConcreteClass>("Fred", "Lives in France");
According to the MSDN documentation on the new constraint:
The new constraint specifies that any type argument in a generic class
declaration must have a public parameterless constructor. To use the
new constraint, the type cannot be abstract.
This refers to the type passed in, not the other constraint on your method.

Partial trust: How to instantiate a generic type without a generic type argument

I'm creating a reusable library for Silverlight. The library contains an internal generic type and I need to create a new instance of this generic type, but I at one point I don't have a generic type argument available, only a System.Type object that represents the generic argument. I tried to create an instance using reflection, but this fails, because this class is internal and Silverlight effectively runs in partial trust.
Here is what I tried so far:
private INonGenericInterface CreateInstance(Type type)
{
// Activator.CreateInstance fails
var instance = Activator.CreateInstance(
typeof(InternalGenericType<>).MakeGenericType(type));
// Invoking the default constructor of that type fails.
var producer = typeof(InternalGenericType<>)
.MakeGenericType(type)
.GetConstructor(new Type[0])
.Invoke(null);
return (INonGenericInterface)producer;
}
This is my internal type. Nothing fancy:
internal class InternalGenericType<T> : INonGenericInterface
where T : class
{
public InternalGenericType()
{
}
}
I even tried abusing the Nullable<T> struct as a factory for creating a factory that could produce my internal type. However, default Nullable<T> get converted to null references:
internal static class InternalGenericTypeFactory
{
public static INonGenericInterface Create(Type serviceType)
{
var nullType = typeof(Nullable<>).MakeGenericType(
typeof(Factory<>).MakeGenericType(serviceType));
// Activator succesfully creates the instance, but .NET
// automatically converts default Nullable<T>s to null.
object nullInstance = Activator.CreateInstance(nullType);
var getValueMethod =
nullType.GetMethod("GetValueOrDefault", new Type[0]);
// Invoke fails, because nullInstance is a null ref.
var factory = getValueMethod.Invoke(nullInstance, null);
return ((IFactory)factory).CreateInstance();
}
internal interface IFactory
{
INonGenericInterface CreateInstance();
}
internal struct Factory<T> : IFactory where T : class
{
public INonGenericInterface CreateInstance()
{
return new InternalGenericType<T>();
}
}
}
As you can imagine, I don't want to make this type public, because it would pollute my API. I'm currently out of ideas. What are my options? What can I do to create this internal type?
Third alternative is to support some sort of factory pattern which will contain a method to instanciate internal type. And you can expose factory or make factory type public.
public class TypeFactory
{
public static object Create<T>()
{
return new MyInternalType<T>();
}
}
You can leave class as internal and you can invoke TypeFactory's method via reflection.
public object CreateType(System.Type type)
{
Type typeFactory = typeof(TypeFactory);
MethodInfo m = typeFactory.GetMethod("Create").MakeGenericMethod(type);
return m.Invoke(null, null);
}
I think your TypeFactory should be public, it can not be internal.
You have two choices:
Make the type public
Avoid using reflection to do this, use generics instead.
If the safeguards were possible to avoid just because you didn't like them, there wouldn't be a need to have them at all.

Categories

Resources