How to generate a Roslyn TypeExpression for a type that has not yet been generated? - code-generation

I have a chicken/egg problem here. I am using SyntaxGenerator to generate some classes. Some of these classes will have fields and properties whose types are types generated in other classes. So my question is how can you declare a field in a class that has a type defined in another generated class that has not yet been generated? Do I have to generate and compile all classes that the currently generated class depends on first?
foreach (var attribute in datatype.Attributes)
{
var fieldName = $"_{MessageNode.FormatResourceName(attribute.Name)}";
var fieldNode = Generator.FieldDeclaration(fieldName, Generator.TypeExpression(**???**), Accessibility.Private);
}
Thanks

You can generate any type name you like, whether the type exists or not, using the SyntaxFactory.
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Simplification;
var name = SyntaxFactory
.ParseTypeName("My.Generated.Type")
.WithAdditionalAnnotations(Simplifier.Annotation);
Alternatively, for a simple name, you can use SyntaxFactory.IdentifierName, for a generic name you can use SyntaxFactory.GenericName. Equivalent API's exist to generate Visual Basic as well.

Related

What is the difference between ::class and ::class.java in Kotlin?

In Java, we write .class (for example: String.class) to get information about the given class. In Kotlin you can write ::class or ::class.java. What is the difference between them?
By using ::class, you get an instance of KClass. It is Kotlin Reflection API, that can handle Kotlin features like properties, data classes, etc.
By using ::class.java, you get an instance of Class. It is Java Reflection API, that interops with any Java reflection code, but can't work with some Kotlin features.
First you need to understand about Reflection. According to the docs:
Reflection is a set of language and library features that allows for introspecting the structure of your own program at runtime.
In simple words, it gives you the ability to get the code you have written i.e., the class name you have defined, the function name you have defined, etc. Everything you have written, you can access all these at runtime using Reflection.
::class and ::class.java are basic features of Reflection.
::class gives you a KClass<T> reference and ::class.java gives you Class<T> reference.
Example,
val a = MyClass::class
can be interpreted as
val a = KClass<MyClass>()
Note: Above code is not syntactically correct, because KClass is an interface and interfaces cannot be instantiated. It is just to give you an idea.
A Class<T> class gives you information about the metadata of the T class like interfaces it is implementing, its functions' names, its package name, etc.
KClass is similar to Class but it gives information about some more properties(Kotlin related properties) than Class. All the information a KClass<T> reference can give you about the T class are listed here https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.reflect/-k-class/#properties
According to the Kotlin documentation, when we create an object using any class type as below the reference type will be type of KClass.
val c = MyClass::class // reference type of KClass
Kotlin class reference is not the same as a Java class reference. To get a Java class reference, use the .java property on a KClass instance.
val c = MyClass::class.java // reference type of Class Java

Getting custom class type returning functions on the Datasnap client autogenerated methods

I am using a TDSServerModule in which I place the functions needed.
When I create the TDSAdminClient with the wizard, I get the autogenerated functions from the TDSServerModule, but not all of them.
Some of the functions need a result types of my custom classes
TStringArray = array of string;
TStringArrayOfString = array of TStringArray;
TStringArrayOfArrayOfString = array of TStringArrayOfString;
Those functions are not autogenerated. I changed the result type of them as TObject in order to get the autogenerated ones in the client side.
Then I changed the type to my custom type again in client and server, but the server does not recognize them any way.
How can this be solved?

Eclipse modeling tool, define a class as a type for an attribut

I try to make a model on eclipse modelling tool and I have in the model a class that use an other class as a type for an attribute.
I have made the class definition but I can't find the way to connect them together.
I have also made the definition for a method with a parameter with the same class type, but there I've no trouble. The class I use as a Type is in the combo box.
How should I do?
If I understand your question correctly, you are trying to create an EMF metamodel, and are using a graphical editor, and try to connect EClasses.
Basically, EMF EClasses can have two kinds of features: EAttributes and EReferences. EAttributes can refer to Java types, like integer or string; while EReferences are used to connect EClasses. In other words, you cannot have an EAttribute refer to another type you added to the diagram; instead you have to create a reference between them.

Intersystems caché - programmatically create new class

Is it possible to write ObjectScript method, which will create new class in namespace and compile it? I mean programmatically create new class and store it. If so, can I edit this class using ObjectScript later(and recompile)?
Reason: I have class structure defined in string variable and I need to add new class to namespace according this string.
Nothing is impossible. Everything in Caché can be created programmatically. And, Classes is not a execution. There are at least two ways to do it:
simple SQL Query CREATE TABLE, will create a class.
and as you already mentioned ObjectScript Code, which can do this.
All of definition of any classes defined in other classes. Which you can find in package %Dictionary.
The class itself defined in %Dictionary.ClassDefinition. Which have some properties, for defining any parts of classes. So, this is a simple code which create some class, with one property.
set clsDef=##class(%Dictionary.ClassDefinition).%New()
set clsDef.Name="package.classname"
set clsDef.Super="%Persistent"
set propDef=##class(%Dictionary.PropertyDefinition).%New()
set propDef.Name="SomeProperty"
set propDef.Type="%String"
do clsDef.Properties.Insert(propDef)
do clsDef.%Save()
And in latest versions, there is one more way for create/change class. If you have text of class as you can see it in Studio. Then, you can load it in Caché, with class %Compiler.UDL.TextServices
Yes, it is. You likely want to make use of %Dictionary.ClassDefinition and the related %Dictionary.*Definition classes (especially %Dictionary.PropertyDefinition, %Dictionary.MethodDefinition and %Dictionary.IndexDefinition) to create and/or modify your class. Provided your string contains some reasonable representation of the data, you should be able to create the class this way.
The actual class documentation is available at http://docs.intersystems.com/cache20141/csp/documatic/%25CSP.Documatic.cls?CLASSNAME=%25Dictionary.ClassDefinition
You can then compile the class by calling $system.OBJ.Compile("YourPackage.YourClass","ck").
(Note: If your string contains the exported XML definition of the class, you could also write the XML representation to a stream and then call $system.OBJ.LoadStream() to import the XML definition. I would only recommend this if you have an exported class definition to start with.)

Record with parameterless constructor?

I'm trying to build a web app (ASP.NET MVC3) that uses Entity Framework, and I've once again hit a wall. It throws following exception when trying to run a foreach loop over the collection in the view:
System.InvalidOperationException: The
class 'GvG.Entities.News' has no
parameterless constructor.
Now is my question, is it possible to somehow define a parameterless constructor on my record type?
My record type at the moment looks like:
type News = {
mutable ID:int;
mutable Author:string;
mutable Title:string;
mutable Content:string }
I'm aware of that I can create a class with baking-fields etc. instead, but thats what I'm trying to avoid.
It's an old one, but I stumbled upon similar issue today, and looks like with F# 3.0 you can overcome it with [<CLIMutable>] attribute: http://msdn.microsoft.com/en-us/library/hh289724.aspx
This way you can use your F# immutable records in many scenarios when C# API requires POCO.
MSDN says "In a record type, you cannot define a constructor."
http://msdn.microsoft.com/en-us/library/dd233184.aspx
I tried to solve this (espeically for Entity Framework) during some contracting project I did for the F# team and you can find an experimental solution in F# PowerPack sources. It is not fully tested & you'd have to build it yourself. The experimental solution replaces all F# tuples and F# records in the query with other (mutable) types and then transforms results back to records/tuples.
EDIT Didn't see the mention about defining class in your question, but I'll leave the example here for others who may come here with the same issue.
There is no easy workaround. The unfortunate solution is to define a class with properties explicitly:
type News() =
let mutable id = 0
let mutable author = ""
let mutable title = ""
let mutable content = ""
member x.ID with get() = id and set(v) = id <- v
member x.Author with get() = author and set(v) = author <- v
member x.Title with get() = title and set(v) = title <- v
member x.Content with get() = content and set(v) = content <- v
That's very ugly compared to records, but it's the only way to do it in the current version of F#. It is something that the F# team is aware of, so there may be some better solution in the next version.