Generate code for classes with an attribute - c#

I have the following setup :
public class CustomAttribute : Attribute
{
[...]
public CustomAttribute(Type type)
{
[...]
}
}
[Custom(typeof(Class2))]
public class Class1
{
public void M1(Class2) {}
public void M2(Class2) {}
}
public partial class Class2
{
[...]
}
What I am trying to achieve using the new Code Generation mechanism added in .NET 5 is at compile-time, find every class in the project referencing my generator being annotated by the Custom attribute, and then, create a partial class for the type in its constructor containing methods having the same name and parameters (It won't be the same parameters, it's just to simplify a bit).
Before, I was planning to use TTs to generate the partial file but creating one per type was announcing itself to be both tedious and hard to maintain.
Thing is...
I'm a little lost.
What I did manage to do:
Create a generator, making sure it is called at generation and the code it generates is usable (~ a hello world version)
Find my attribute symbol in the compilation context (not sure I'll need it, but I found it)
Found a way to identify the classes being annotated by my attribute by relying on the syntax trees present in the compilation context.
Now, though I don't know how to proceed further, the syntax tree has at the same level the identifier nodes for my attribute and the class being used as a parameter, meaning if I ever use another attribute, I fear they will all get at the same level (might use the order getting the position of the identifier for my attribute and then getting the next one).
But then even if we omit that... How can I list all methods and their parameters for a given class that I have the name of? Reflection is obviously out of the picture since the assembly is not loaded.
I only found Rosly examples, based on using the solution or Analyzers who don't really have the same type of objects available, and thus the proposed solutions are not applicable. And I'm not sure starting another Roslyn analysis on single files is really the way it is supposed to be done.

Please keep in mind that this is my first foray with the Semantic/Syntaxic API.
Preparatory work: Introduction to C# source generators
This will guide you towards settings up a code generator project. As far as I understood, tooling is on the way to automate this part.
TL;DR there will be the full ExecuteMethod at the end of this answer
Filtering out the syntaxic trees containing no classes decorated with an attribute
This is our first step, we only want to work with the classes that are decorated by an attribute, we'll then make sure it's the one that interests us. This also has the secondary benefit of filtering out any source files that do not contain classes (think AssemblyInfo.cs)
In the Execute method of our new Generator, we will be able to use Linq to filter out the trees:
var treesWithlassWithAttributes = context.Compilation.SyntaxTrees.Where(st => st.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()
.Any(p => p.DescendantNodes().OfType<AttributeSyntax>().Any()));
We will then be able to loop on our syntaxic trees (from what I could see, one syntaxic tree corresponds roughly to one file)
Filter-out classes not being annotated with an attribute
The next step is to make sure that in our current syntaxic tree, we only work on classes being decorated by an attribute (for the cases where several classes are declared in one file).
var declaredClass = tree
.GetRoot()
.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.Where(cd => cd.DescendantNodes().OfType<AttributeSyntax>().Any())
This is all pretty similar to the previous step, tree being one of the items we got in our treesWithClassWithAttributes collection.
Once again, we'll loop on that collection.
Filter-out classes that are not annotated with our specific attribute
Now, that we are working on single classes, we can dive in and check if any of the attributes are the one we are looking for. This will also be the first time we will need the semantic API, since the attribute identifier is not it's class name (PropertyAttribute, will be used as [Property] for example), and the semantic API, allows us to find the original class name without us having to guess.
We will first need to initialize our semantic model (this should placed in our top level loop):
var semanticModel = context.Compilation.GetSemanticModel(tree);
Once initialized, we get to our searching :
var nodes = declaredClass
.DescendantNodes()
.OfType<AttributeSyntax>()
.FirstOrDefault(a => a.DescendantTokens().Any(dt => dt.IsKind(SyntaxKind.IdentifierToken) && semanticModel.GetTypeInfo(dt.Parent).Type.Name == attributeSymbol.Name))
?.DescendantTokens()
?.Where(dt => dt.IsKind(SyntaxKind.IdentifierToken))
?.ToList();
Note: attributeSymbol is a variable holding the Type of the attribute I am searching for
What we are doing here, is for each syntaxic node related to our class declaration, we only look at the ones describing an attribute declaration.
We then take the first one (my attribute can only be placed once on a class) that has an IdentifierToken for which the parent node Is of the type of my attribute (the semantic API does NOT return a Type hence the name Comparison).
For the next steps, I will need the IdentifiersToken, so we'll use the Elvis operator to get them if we found our attribute, we'll get a null result otherwise which will allow us to get to the next iteration of our loop.
Get the class type used as my Attribute parameter
This is where it gets really specific to my use case, but it's part of the question, so I'll cover it anyway.
What we got at the end of the last step was a list of Identifier Tokens, which mean, we will have only two for my attribute : The first one Identifying the attribute itself, and the second one identifying the class I want to get the name of.
We will be using the semantic API again, this allows me to avoid looking in all the syntax trees to find the class we identified :
var relatedClass = semanticModel.GetTypeInfo(nodes.Last().Parent);
This gives us an object similar to the ones we were manipulating until now.
This is a good point to start generating our new class file (so a new stringbuilder, with all the test needed to have a partial class in the same namespace the other one was, it will always be the same in my case, so I went and wrote it directly)
To get the name of the type in relatedClass => relatedClass.Type.Name
List all methods used in a class
So now, to list all the methods in the annotated class. Remember we are looping on classes here, coming from our syntactic tree.
To obtain a list of all the methods declared in this class we will ask to list the member of type method
IEnumerable<MethodDeclarationSyntax> classMethod = declaredClass.Members.Where(m => m.IsKind(SyntaxKind.MethodDeclaration)).OfType<MethodDeclarationSyntax>()
I will strongly recommend either casting to MethodDeclarationSyntax or assigning to a variable with the explicit type, because it is stored as a base type that does not expose all of the properties we'll need.
Once we've got our methods, we will once again loop on them.
Here are the few properties I needed for my use case :
methodDeclaration.Modifiers //public, static, etc...
methodDeclaration.Identifier // Quite obvious => the name
methodDeclaration.ParameterList //The list of the parameters, including type, name, default values
The rest was just a matter of constructing a string representing my target partial class which is now a pretty simple matter.
The final solution
Remember that's what I came up with as my first try, I will most probably submit it on the CodeReview StackExchange to see what could be improved.
And the RelatedModelaAttribute is basically the CustomAttribute class from my question.
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using SpeedifyCliWrapper.SourceGenerators.Annotations;
using System.Linq;
using System.Text;
namespace SpeedifyCliWrapper.SourceGenerators
{
[Generator]
class ModuleModelGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
var attributeSymbol = context.Compilation.GetTypeByMetadataName(typeof(RelatedModelAttribute).FullName);
var classWithAttributes = context.Compilation.SyntaxTrees.Where(st => st.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>()
.Any(p => p.DescendantNodes().OfType<AttributeSyntax>().Any()));
foreach (SyntaxTree tree in classWithAttributes)
{
var semanticModel = context.Compilation.GetSemanticModel(tree);
foreach(var declaredClass in tree
.GetRoot()
.DescendantNodes()
.OfType<ClassDeclarationSyntax>()
.Where(cd => cd.DescendantNodes().OfType<AttributeSyntax>().Any()))
{
var nodes = declaredClass
.DescendantNodes()
.OfType<AttributeSyntax>()
.FirstOrDefault(a => a.DescendantTokens().Any(dt => dt.IsKind(SyntaxKind.IdentifierToken) && semanticModel.GetTypeInfo(dt.Parent).Type.Name == attributeSymbol.Name))
?.DescendantTokens()
?.Where(dt => dt.IsKind(SyntaxKind.IdentifierToken))
?.ToList();
if(nodes == null)
{
continue;
}
var relatedClass = semanticModel.GetTypeInfo(nodes.Last().Parent);
var generatedClass = this.GenerateClass(relatedClass);
foreach(MethodDeclarationSyntax classMethod in declaredClass.Members.Where(m => m.IsKind(SyntaxKind.MethodDeclaration)).OfType<MethodDeclarationSyntax>())
{
this.GenerateMethod(declaredClass.Identifier, relatedClass, classMethod, ref generatedClass);
}
this.CloseClass(generatedClass);
context.AddSource($"{declaredClass.Identifier}_{relatedClass.Type.Name}", SourceText.From(generatedClass.ToString(), Encoding.UTF8));
}
}
}
public void Initialize(GeneratorInitializationContext context)
{
// Nothing to do here
}
private void GenerateMethod(SyntaxToken moduleName, TypeInfo relatedClass, MethodDeclarationSyntax methodDeclaration, ref StringBuilder builder)
{
var signature = $"{methodDeclaration.Modifiers} {relatedClass.Type.Name} {methodDeclaration.Identifier}(";
var parameters = methodDeclaration.ParameterList.Parameters.Skip(1);
signature += string.Join(", ", parameters.Select(p => p.ToString())) + ")";
var methodCall = $"return this._wrapper.{moduleName}.{methodDeclaration.Identifier}(this, {string.Join(", ", parameters.Select(p => p.Identifier.ToString()))});";
builder.AppendLine(#"
" + signature + #"
{
" + methodCall + #"
}");
}
private StringBuilder GenerateClass(TypeInfo relatedClass)
{
var sb = new StringBuilder();
sb.Append(#"
using System;
using System.Collections.Generic;
using SpeedifyCliWrapper.Common;
namespace SpeedifyCliWrapper.ReturnTypes
{
public partial class " + relatedClass.Type.Name);
sb.Append(#"
{");
return sb;
}
private void CloseClass(StringBuilder generatedClass)
{
generatedClass.Append(
#" }
}");
}
}
}

Inside the Execute method of your generator, add this:
var classesWithAttribute = context.Compilation.SyntaxTrees
.SelectMany(st => st.GetRoot()
.DescendantNodes()
.Where(n => n is ClassDeclarationSyntax)
.Select(n => n as ClassDeclarationSyntax)
.Where(r => r.AttributeLists
.SelectMany(al => al.Attributes)
.Any(a => a.Name.GetText().ToString() == "Foo")));
This basically takes all the nodes of all the trees, filters out nodes that are not class declarations, and, for each class declaration, looks if any of its attributes matches our custom attribute, "Foo" here.
Note: if your attribute is named FooAttribute, then you look for Foo, not FooAttribute.

// In SourceGenerator
public void Initialize(GeneratorInitializationContext context)
{
#if DEBUG
if (!Debugger.IsAttached)
{
//Debugger.Launch();
}
#endif
context.RegisterForSyntaxNotifications(() => new MySyntaxReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
MySyntaxReceiver syntaxReceiver = (MySyntaxReceiver)context.SyntaxReceiver;
}
class MySyntaxReceiver : ISyntaxReceiver
{
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
// Note that the attribute name, is without the ending 'Attribute' e.g TestAttribute -> Test
if (syntaxNode is ClassDeclarationSyntax cds && cds.AttributeLists.Count > 0)
{
var syntaxAttributes = cds.AttributeLists.SelectMany(e => e.Attributes)
.Where(e => e.Name.NormalizeWhitespace().ToFullString() == "Test")
if (syntaxAttributes.Any())
{
// Do what you want with cds
}
}
}
}

Related

Detect access to data from a method in c#

I have a method and I want to find all data accessed inside this method.
for example:
public class foo
{
private int field;
public void method()
{
field = 0;
}
}
I need a way to know (from the source code or the assembly) that 'field' is accessed within 'method'.
Note: I already used Harmony Library (https://github.com/pardeike/Harmony) to find all the calls to methods inside a specific method. It would be amazing if someone knows how to use it to also find data accessed.
as pointed out in comments, Roslyn DataFlowAnalysis is probably the best tool for the job:
SyntaxTree tree = CSharpSyntaxTree.ParseText(
#"public class foo
{
private int field;
public void method()
{
field = 0;
}
}");
var compilation = CSharpCompilation.Create("test").AddSyntaxTrees(tree).AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));
var model = compilation.GetSemanticModel(tree);
var methodDeclaration = tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().First();
var dataFlow = model.AnalyzeDataFlow(methodDeclaration.Body);
foreach (var symbol in dataFlow.DataFlowsIn)
{
Console.WriteLine(symbol.Name, symbol.Kind);
}
analysis for your particular example yields reference to class foo through implicit
this, but not the field itself (which is technically correct but not very helpful). Assuming your actual code will likely have a bit more dependencies in it - you may see better results.
If you look at the list of opcodes in IL you find that you want to search for OpCodes.Ldfld and OpCodes.Ldflda. Harmony’s CodeInstruction has two fields to use: compare code to either opcode and use operand and cast it to a FieldInfo to learn about what field is read. Use OpCodes.Stfld(a) for write access to fields.

C#, Generics, Type and NHibernate

I'm learning the power of generics in C# in conjunction with NHibernate. I'd like to attempt the following in the pasted code.
In an attempt to do some post processing of N number of NHibernate objects I worked on a utility method leveraging generics to make it applicable to all NHibernate mapping classes we use now, or in the future. It works but I need to hard code each call for each mapping class. This is a pain and will need continuing updating as our schema and mappings change over time.
I do have an ever up-to-date list of all mapping classes by string name through the NHibernate mappings I generate on the fly. If there was a way to use this list of string names to call my generics based method, I'd be super happy.
Can anyone tell me if this is possible? Do I need to find another route?
Thanks so much in advance!!!
public static void ProcessSomeItems()
{
// *************************************************************
// As of now I have to list all classes as such to be processed
// It works but I have to update manually when new mapping classes are created
// *************************************************************
NHibDoSomethingUtil<AspnetMembership>();
NHibDoSomethingUtil<AspnetProfile>();
NHibDoSomethingUtil<AspnetRole>();
NHibDoSomethingUtil<AspnetUser>();
// and so forth...
// I have a up-to-date list of all mappings from "HbmMapping" and can get a list of all in the
// list form as below
List<string> mappingNames = new List<string>();
foreach (string mappingName in mappingNames)
{
Type theType = Type.GetType(mappingName);
// I know I'm getting Types and Generics classes and so forth all jumbled but
// how in the heck would I do something like the below?
NHibDoSomethingUtil<theType>(); // Obviously doesn't compile ;-)
}
}
// Generic method
public static void NHibDoSomethingUtil<T>() where T : class
{
using (ISession session = sourceDBSessionFactory.OpenSession())
{
foreach (dynamic item in new List<T>(session.QueryOver<T>().List()))
{
// Process item;
}
}
}
ecsousa gave great input and I was able to accomplish what I needed with something like the following.
foreach (HbmClass mappingClass in mapping.Items)
{
Console.WriteLine(" -- Discovered Mapping: " + mappingClass.Name);
Type mappingClassType = Type.GetType(mappingClass.Name);
var genericMethod = typeof(Migration).GetMethod("NHibDoSomethingUtil");
var method = genericMethod.MakeGenericMethod(mappingClassType);
method.Invoke(null, null);
}
You will need to use Reflection in order to accomplish this. Instead of directly calling NHibDoSomethingUtil, try this:
var genericMethod = typeof(TheClassName).GetMethod("NHibDoSomethingUtil");
var method = genericMethod.MakeGenericMethod(theType);
method.Invoke(null, null);
Note that you have to replace TheClassName by the class containing both methods.
Keep in mind the this kind of code is slow, and you should use it very carefully.

Extracting the value from a Member Expression that contains a parameter

How do I extract a value from a Member Expression where the expression within the Member Expression is not a Constant, but a Parameter Expression.
I am building a small Linq to MDX ORM for our company.
In my generator template, each Dimension found in the database is a class, and in each dimension, there are the Attribute properties that are found for that dimension. After all the dimension classes are generated, a higher level Cube class is generated that contains the Dimensions as properties, as well as the Measures for that cube. After all the cube classes are generated, a final class is built that contains the cube classes that were generated as Cube<MyCube> properties, where the Cube<> is my IQueryable type. Here's an example.
//Generated cs file example:
public partial MyDatabase : CubeBase
{
//Some base implementation goes here
public Cube<FooCube> FooCube { get { return new Cube<FirstCube>(new Provider("connection string"); } }
//Any other cubes would follow here that were found on this database.
}
//A calendar dimension
public class FooCube_CalendarDimension
{
public Attribute WeekEnding { get { return new Attribute("[Calendar].[Week Ending]"); } }
public Attribute Month { get { return new Attribute("[Calendar].[Month]"); } }
public Attribute Year { get { return new Attribute("[Calendar].[Year]"); } }
}
//The "FooCube"
public partial class FooCube
{
//List Dimensions
public FooCube_Calendar_Dimension Calendar { get { return new FooCube_Calendar_Dimension(); } }
//Other dimensions here
[Measure]
public string RetailDollars { get { return "[Retail Dollars]"; } }
// Other measures here
}
Now, an example of a very basic linq query to query the cube:
//using MyDatabase = db
var mdx = from cube in db.FooCube
where cube.Calendar.Year == "2014"
select new
{
Month = cube.Calendar.Month.Children
Dollars = cube.RetailDollars
}
For example, I'm trying to get the value from cube.Calendar.Month.Children, which comes from the Attribute object that is a property of the FooCube_Calendar_Demsion class, that is in itself a property in the "FooCube" class.
I tried the answer from Access the value of a member expression, but I get the error, "the 'cube' parameter was not referenced" when it tries to compile the lambda expression. The value that it passes to the attribute class's constructor is stored in a property, and that's the value (one of them) that I want to access.
Basically, you can't. At least, not in any sensible way. Currently all that you have is a query. You don't actually have a collection of objects, you just have information about what you need to do to create those objects. It is the job of the query provider that you're currently in the process of writing to actually build the objects that the query defines and return them.
You've designed your program such that the query provider that creates the objects needs to have the already created objects already in order to properly build the query. It's impossible to already have the objects defined by the query that you haven't built yet. You've created a circular dependency for yourself.
It's important for you to provide the information needed to build the query somewhere other than in instances the objects that the query itself creates. Typically this is done with attributes on the properties, or by basing the query on the other existing C# metadata about the type itself. This type data exists, and is accessible to your query provider without needing any actual instances of the objects you're tasked with creating.
I'm adding this answer because I found two ways of extracting the value that I want. I want to thank Servey though for his answer as he was indeed correct about not doing it in any sensible way in that I had my code written.
What I found was two ways of going about this.
Using a generic translator class with a generic parameter that was the class type of the parameter that my lambda expression was wanting, and then using that generic parameter as the input parameter on the Func<object, T> delgate. This is the best and fastest way of doing it, as there is no dynamic operations going on during runtime.
var lambda = Expression.Lambda<Func<object, T>>(//Expressions here);
The second way I found is slower as it involves the Delegate.DynamicInvoke() method, but it does work.
var lambda = Expression.Lambda(member, (ParameterExpression)member.Expression);
var d = lambda.Compile();
return d.DynamicInvoke(member.Expression.Type.GetConstructors()[0].Invoke(new object[0]));
This will get the object's value but is costly due to the dynamic invoke.

Roslyn CTP - Random Code Modification

I have been experimenting with the Roslyn API in a genetic programming type of scenario. It appears like a great way to do that type of programming, but the actual implementation of simple scenarios doesn't seem very straightforward, which means I probably don't have a good understanding of how to use this API properly. Here is a simple program I am trying to modify in my experiments:
string treeText = #"using System;
using System.Collections.Generic;
namespace TestProgram
{
class Program
{
static void Main(string[] args)
{
var myVar = 3;
string myString = ""Hello World"";
List<string> stringList = new List<string>();
Console.WriteLine(myString + myVar);
Console.ReadLine();
}
}
}";
SyntaxTree tree = SyntaxTree.ParseText(treeText);
var compilation = Compilation.Create("test.exe",
syntaxTrees: new[] { tree },
references: new[]
{
new MetadataFileReference(typeof(object).Assembly.Location),
new MetadataFileReference(typeof(Enumerable).Assembly.Location),
});
SemanticModel model = compilation.GetSemanticModel(tree);
Just as a simple example let's say I somehow "randomly" decided I want to insert a new method invocation using the myString instance. What would be an efficient way to figure out what methods I could invoke off of that instance? What would then be the best way to create the necessary MethodInvocationSyntax (once I chose a specific method to use) from the symbol information? I found a method called ResolveOverloads on the SemanticModel class which appears where I need to end up, but I am having some difficulty figuring out an efficient path to the parameters this method requires. Is that even the right path to go down?
First, get the VariableDeclaratorSyntax for your variable, for example:
var variable = tree.GetRoot().DescendantNodes()
.OfType<VariableDeclaratorSyntax>()
.Single(v => v.Identifier.ValueText == "myString");
Next, get the LocalSymbol for this variable from the SemanticModel:
var variableSymbol = (LocalSymbol)model.GetDeclaredSymbol(variable);
Then you can get a list of methods you can invoke on this variable based on its type. You can either simply get all members of the type that are instance methods:
var methods =
variableSymbol.Type.GetMembers()
.OfType<MethodSymbol>()
.Where(m => !m.IsStatic && m.MethodKind == MethodKind.Ordinary);
Or, if you wanted to include extension methods, you could use LookupSymbols():
var methods = model.LookupSymbols(
variable.GetLocation().SourceSpan.Start, variableSymbol.Type,
options: LookupOptions.IncludeExtensionMethods)
.Where(m => !m.IsStatic);
You can then choose one of the available methods based on your logic and create InvocationExpressionSyntax (the following code assumes it's a parameterless method):
var invocationExpression =
Syntax.InvocationExpression(
Syntax.MemberAccessExpression(
SyntaxKind.MemberAccessExpression,
Syntax.IdentifierName(variableSymbol.Name),
(SimpleNameSyntax)Syntax.ParseName(selectedMethod.Name)));
You would then need to figure out where in your method to add the expression and what to do with its result (if anything).

Calling custom (formatting) method on LINQ to Entities

I'm using EF 4.1 and I'm trying to enumerate a company list for a grid. I have two options in the current project: select all companies from the DbContext (Entities) and load them into an object from a non-anonymous type (let's say EmpresaGrid) or select all companies into anonymous type objects with the same structure like Empresa (which is the entity I'm selecting from).
The first option (creating a model class for that) would require a little more work, but can be, eventually, more readable. Still, I'm not sure about that. The second option is what I'm using right now.
So, first question: it's better to create a model class only for displaying data or use anonymous type? Doing a direct select is out of question: a SELECT * is too big and that might make everything damn slow (I guess). So selection into another type creates a custom query with only the needed fields.
Using the second option (anonymous type), I have this code (simplified version):
public static IEnumerable<object> Grid()
{
Entities db = new Entities();
var empresas = db.Empresas
.Select(e => new
{
Cgc = e.Cgc, // PK
(...)
Address = new
{
AddressLine = e.EnderecoSede.AddressLine,
(...)
}
},
Contato = e.Contato,
(...)
})
.ToList();
return empresas;
}
The anonymous type I'm creating has around 40 lines of code, so it's kinda big, but it recreates part of the Empresa class struct (since the grid is waiting for a Empresa object). Anyway, I have a problem with the data format. For example, I would like to format the Cgc property using a custom string format. I have a public method for this, FormataCgc. This method receives a string and returns it formatted using some internal conditions.
So, my problem is how to that. For example, I have tried this:
var empresas = db.Empresas
.Select(e => new
{
Cgc = FormataCgc(e.Cgc),
}
But that doesn't work because FormataCgc cannot be translated into SQL (and I don't want to convert it). I also tried this:
var empresas = db.Empresas
.Select(e => new
{
(...)
}
.ToList();
foreach (var e in empresas) {
e.Cgc = FormataCgc(e.Cgc);
}
But it cannot be done since anonymous types have only read-only properties.
So, my second question is: how exactly can I do that? I need to change the data after selecting it, but using anonymous types? I've done a little research, and the best thing I've found was this: Calling a custom method in LINQ query. In that solution, Ladislav suggested doing a second select from the IEnumerable, but since the grid is excepting Empresa I cannot do that (I need to change or add properties, not encapsulate them).
I'm not sure if I was clear enough, but feel free to ask any questions. Also, the grid I'm currently using is a Telerik ASP.NET MVC Grid, which receives a IEnumerable (where T is a class) as model data and them iterates each object, doing its magic.
Since you're already converting this into an IEnumerable<T>, you can do the custom formatting as you stream the results in the client. Do your db.Select, and then convert to the appropriate format afterwards, ie:
var empresas = db.Empresas
.Select(e => new
{
(...)
})
.ToList();
foreach (var e in empresas) {
yield return new {
Cgc = FormataCgc(e.Cgc),
// Copy other properties here, as needed...
};
}
That being said, I'd personally recommend making a custom class, and not return an anonymous type. Your conversion would then be:
foreach (var e in empresas) {
yield return new YourClass(FormataCgc(e.Cgc), ...); // Construct as needed
}
This will dramatically improve the usability of this method, as you will have proper, named access to your properties from the caller of the method.
I think the solution to both of your questions is to create a model class. Sure it is a little bit more work up front, but it will allow you greater flexibility in the long run. Your custom model class can then handle the formatting for you.
public class EmpresaGridModel
{
public string Cgc { get; set; }
public string CgcFormatted
{
return FormataCgc(this.Cgc);
}
//properties for the other fields will have to be created as well obviously
}
Your telerik grid can then bind directly to the CgcFormatted property

Categories