Is there any way to use extension methods on a class that has been dynamically created using Relection.Emit? For example:
class somewhere
{
somewhere()
{
// define the type here using ReflectionEmit, etc.
Type tableType = CreateTableType(...table parameters...);
var table = Activator.CreateInstance(tableType);
table.Shuffle();
}
}
//... elsewhere
public class static TableTypeExtensions
{
public static Table Shuffle( this Table t)
{
...
}
}
But I don't have the class by name "Table", only Type tableType available.
Is there any way around this?
Thanks
Make the dynamic class implement an interface (an empty one if you want), add extensions to the interface.
Define a common base class for your TableType and define the extension method on that. This way your extension method should be available for the derived classes as well.
Let's look at what you're asking.
You're asking how to get the extension method to operate on your object instance.
Obviously, for this to work, it has to be a Table, otherwise your question makes no sense.
So just cast it to Table:
var table = (Table)Activator.CreateInstance(tableType);
and you can call your extension method just fine.
In your somewhere code do you have reference to the type Table? If so you can:
Type tableType = CreateTableType(...table parameters...);
var table = Activator.CreateInstance(tableType) as Table;
table.Shuffle();
Related
I have a custom class Customer and inside another class a method that returns a list based on a LiteCollection from LiteDB typized using the Customer class in the signature. What I wanted to know is if it’s possible creating a method that dynamically chooses which class uses a type, meaning if I can pass as a parameter the class type of the LiteCollection to return when I call the method.
The code is as follows:
public static LiteCollection<Customer> GetCustomers()
{
var collection = ConnectToDB().GetCollection<Customer>("customers");
return collection;
}
How about:
public static LiteCollection<T> Get(string tableName)
{
return ConnectToDB().GetCollection<T>(tableName);
}
That would be called:
var table = Get<Customer>("customers");
Update
Unfortunately it is not really possible to get rid of the generic type, cause otherwise your consuming code doesn't know what it gets back. So the minimum that would be possible would be
var table = Get<Customer>();
In that case your implementation needs some kind of mapper from type to table name. For this purpose I could think of three possibilities (which you could also combine):
The class has an internal Dictionary<Type, string> where all table names for a given type is manually entered.
The convention is that for every T the table name is a pluralized string of the type name, then you need a pluralize method that returns Pluralize(typeof(T).Name).
By reflection you iterate over your derived DBContext, get out all DBSet<> properties and pre-fill the dictionary out of the first possibility by using the generic argument from DBSet<> and the property name.
I'm wondering if the following can be refactored in the way I would like it:
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ListExtensions
{
public static PaginatedList<Y> ToMappedPaginatedList<T, Y>(this PaginatedList<T> source)
{
var mappedList = new List<Y>();
Mapper.Map(source, mappedList);
return new PaginatedList<Y>(mappedList, source.PageIndex, source.PageSize, source.TotalCount);
}
}
The Mapper.Map line is using AutoMapper to map properties from an entity to a DTO object.
This is called like this:
var list = await _service.GetAllAsync(pageIndex, _pageSize);
var dtoList = list.ToMappedPaginatedList<Farmer, FarmerDTO>();
but I'd like to call it like this:
var dtoList = list.ToMappedPaginatedList<FarmerDTO>();
This saves a little bit of typing and you don't always need to be aware of the source list its type. Unfortunately this code doesn't work and I'm not sure if there's a simple answer.
Anyone got an idea?
Thanks in advance.
Yannick
If you have access to the PaginatedList class, putting the method in there will enable the syntax you desire since the instance knows what it's own type is.
I don't recommend the following but it demonstrates a way to take advantage of type inference.
You can enable type inference by adding a 2nd "useless" parameter of type Y.
If you pass default(FarmerDTO) as the 2nd parameter, a null will be passed as the parameter value but the intended type will be inferred.
[EditorBrowsable(EditorBrowsableState.Never)]
public static class ListExtensions
{
public static PaginatedList<Y> ToMappedPaginatedList<T, Y>(this PaginatedList<T> source, Y destinationPlaceholder)
{
var mappedList = new List<Y>();
Mapper.Map(source, mappedList);
return new PaginatedList<Y>(mappedList, source.PageIndex, source.PageSize, source.TotalCount);
}
}
Call it like this:
var result1 = s.ToMappedPaginatedList(default(FarmerDTO));
Fair warning. I've never used this because I find the resulting code to be non-obvious as to what it is doing.
Either you call a method and specify all the generic arguments or you specify none and let the compiler infer them, there's no support for partial inference.
As such, the only way to get your code to compile is to make ToMappedPaginatedList take 1 generic parameter, instead of two.
I have many classes in a program but almost all of them have the same methods and call almost the same stored procedures in a SQL Server. The difference in the name is the name of the class ( "pa" + class + CRUD). Is there a way to create a common calling method?
I want to make a method that, called from, let's say, the Student class, would call "paStudentSelect" and return a Student object; and if the method is called from the Teacher class the called SP is "paTeacherSelect" and return a Teacher object.
Extra: I have to check for nulls that vary from class to class. Using a string array as a parameter would be possible to check the properties of the class named in the string array?
PS: I know the thing to do is refactor and think again the code, the tables and the SPs but it's not my program.
As you've described your class name, this should do it:
var proc_name = string.Format("pa{0}delete", GetType().Name);
Extra: yes. Using reflection you can get a PropertyDescriptor for the class named in the string array or, if you want, the Type array...
var types = new Type[] { typeof(Student), typeof(Teacher), ... };
foreach(var t types)
{
// todo: perform your null checks here
var proc_name = t.Name;
db.ExecuteSQLCommandOrWhatever(proc_name);
}
I don't see why you would want to do such a thing. You say that you want to be able to call a common method from different classes(Student, Teacher, etc). If you were calling the method from a common place it made more sense to create a common method but when you are actually calling the method from the classes themselves you might as well call the appropriate SP and avoid the pitfalls with the type of approach you should take(code breaks with name changes and possibly more).
If you absolutely have to do this I can think of two possible solutions:
1) Extension Methods: create a common abstact type(you probably have one already) for your classes and add an extension method for that abstract class. The method could be something like this:
protected void CallCRUD(this AbstractType obj)
{
//call SP on this.TableName
}
2) Generic Method: create a static generic method:
public static T CallCRUD<T>()
{
//call SP on typeof(T).Name
}
Your "Extra:" is very vague so I don't have an answer for you there.
I have a table in my database that I use to manage relationships across my application. it's pretty basic in it's nature - parentType,parentId, childType, childId... all as ints. I've done this setup before, but I did it with a switch/case setup when I had 6 different tables I was trying to link. Now I have 30 tables that I'm trying to do this with and I would like to be able to do this without having to write 30 case entries in my switch command.
Is there a way that I can make reference to a .Net class using a string? I know this isn't valid (because I've tried several variations of this):
Type t = Type.GetType("WebCore.Models.Page");
object page = new t();
I know how to get the Type of an object, but how do I use that on the fly to create a new object?
This link should help:
https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance
Activator.CreateInstance will create an instance of the specified type.
You could wrap that in a generic method like this:
public T GetInstance<T>(string type)
{
return (T)Activator.CreateInstance(Type.GetType(type));
}
If the type is known by the caller, there's a better, faster way than using Activator.CreateInstance: you can instead use a generic constraint on the method that specifies it has a default parameterless constructor.
Doing it this way is type-safe and doesn't require reflection.
T CreateType<T>() where T : new()
{
return new T();
}
public static T GetInstance<T>(params object[] args)
{
return (T)Activator.CreateInstance(typeof(T), args);
}
I would use Activator.CreateInstance() instead of casting, as the Activator has a constructor for generics.
You want to use Activator.CreateInstance.
Here is an example of how it works:
using System;
using System.Runtime.Remoting;
class Program
{
static void Main()
{
ObjectHandle o = Activator.CreateInstance("mscorlib.dll", "System.Int32");
Int32 i = (Int32)o.Unwrap();
}
}
Assuming you have the following type:
public class Counter<T>
{
public T Value { get; set; }
}
and have the assembly qualified name of the type, you can construct it in the following manner:
string typeName = typeof(Counter<>).AssemblyQualifiedName;
Type t = Type.GetType(typeName);
Counter<int> counter =
(Counter<int>)Activator.CreateInstance(
t.MakeGenericType(typeof(int)));
counter.Value++;
Console.WriteLine(counter.Value);
Here is a function I wrote that clones a record of type T, using reflection.
This is a very simple implementation, I did not handle complex types etc.
public static T Clone<T>(T original)
{
T newObject = (T)Activator.CreateInstance(original.GetType());
foreach (var prop in original.GetType().GetProperties())
{
prop.SetValue(newObject, prop.GetValue(original));
}
return newObject;
}
I hope this can help someone.
Assaf
I have a class ReportingComponent<T>, which has the constructor:
public ReportingComponent(IQueryable<T> query) {}
I have Linq Query against the Northwind Database,
var query = context.Order_Details.Select(a => new
{
a.OrderID,
a.Product.ProductName,
a.Order.OrderDate
});
Query is of type IQueryable<a'>, where a' is an anonymous type.
I want to pass query to ReportingComponent to create a new instance.
What is the best way to do this?
Kind regards.
Write a generic method and use type inference. I often find this works well if you create a static nongeneric class with the same name as the generic one:
public static class ReportingComponent
{
public static ReportingComponent<T> CreateInstance<T> (IQueryable<T> query)
{
return new ReportingComponent<T>(query);
}
}
Then in your other code you can call:
var report = ReportingComponent.CreateInstance(query);
EDIT: The reason we need a non-generic type is that type inference only occurs for generic methods - i.e. a method which introduces a new type parameter. We can't put that in the generic type, as we'd still have to be able to specify the generic type in order to call the method, which defeats the whole point :)
I have a blog post which goes into more details.