I'm using AnTLR's plugin for C# in Visual Studio 2015. AnTLR has a class ParserRuleContext from which all the parser rule classes inherit. The parser rule classes themselves are declared as partial classes, like this:
public partial class SomeRuleContext : ParserRuleContext {
/* stuff goes here */
}
The definition of ParserRuleContext looks like this:
public class ParserRuleContext : RuleContext
{
}
I'm implementing my own partial classes for all parser rules to do custom stuff with the parser tree. I would like to be able to add a property to the ParserRuleContext (and other properties/fields/methods later), but ParserRuleContext is not declared as partial. Since the rule classes all already inherit from another class, I can't make my partial implementations of them also inherit from a class. Extension methods don't get me all the functionality I want (can't add properties/fields), and Interfaces have me literally copy/pasting the exact same code into every class. As a software developer, that last part almost literally makes me nauseous.
I have considered the idea of adding a single, constant property that points at an object that contains the functionality I want, but that solution feels clunky to me and adds an extra call to any of the members of the type. So this:
SomeRuleContextInstance.CustomProperty = new FileInfo( "path" );
becomes this:
SomeRuleContextInstance.CommonFunctionality.CustomProperty = new FileInfo( "path" );
I would prefer a better solution.
Can anyone provide a way to either modify the ParserRuleContext base class or otherwise not have me copy/paste code everywhere? Could this be done with Reflection?
You can add an additional inheritance level between the concrete context classes and ParserRuleContext.
Just create a class that inherits ParserRuleContext:
public abstract class MyParserRuleContext : ParserRuleContext
{
// Whatever you want here
}
And then tell your grammar to use it with the following option:
grammar MyGrammar;
options {
contextSuperClass = MyParserRuleContext;
}
// ...
Related
Is it possible to define a compiler constant on a PER-FILE/project-item basis ?
Background:
I want to achieve a Database Abstraction Layer (DAL), that separates all read, and write tasks, but retain a DAL that can do both, but without implementing the same methods multiple times (abstract class means there will be 1 instance class for every supported database type).
So I want to separate my DAL like this:
abstract class ReadDAL
abstract class WriteDAL
abstract class ReadWriteDAL (multiple-inheritance from Read&Write-DAL).
Unfortunately, that doesn't work, because C# doesn't support multiple inheritance.
So one way around this problem would be by defining interfaces:
abstract class ReadDAL : IReadDAL
abstract class WriteDAL : IWriteDAL
abstract class ReadWriteDAL : IReadDAL, IWriteDAL
However, if I do this, I'll have to change the interface definition every time I change a method in one of the DALs, and change the methods defined in ReadWriteDAL, and I have to copy-paste somewhere the method implementation, which means there will be a DRY-noncompliance mess.
I figured what I could do was adding the same file a second time as link, and having a define on a per-project-item basis:
#if SOMECONSTANT // true if file is PartialReadDAL.cs
public partial abstract class ReadDAL
#else // false if "file" is link called "PartialReadWriteDAL.cs" symlinking to PartialReadDAL.cs
public partial abstract class ReadWriteDAL
#endif
and here some implementation.
But can I somehow define a compiler constant per file ?
Or achieve a similar effect somehow ?
The symlink route would be very, very confusing. When forced into doing this, I would implement that by prepending some #defines into relevant files as a prebuild step. Then I would #if on presence of these symbols in the code. I wouldn't like this at all though: my guess is that this would not be as transparent as I would like even if I cleared this markers after build's end so it won't get in version control.
Is ReadWriteDAL going to contain some state of it's own, or is it going to be just a dispatcher for method calls into ReadDAL and WriteDAL? If it's just a dispatcher, you might consider to drop actual implementation (ReadWriteDAL) and pass calls to IReadDAL and IWriteDAL as registered in composition root, using dynamic proxy mechanism. I wrote a tool like that for Castle Windsor.
I'm currently using .Settings files to store level data (Level1.settings, Level2.settings) in a WinForms application. Please nevermind why I would do that :) I'm currently reading each level with a different function, because I can't figure out how to pass to a function.
In my application I have:
AppTitle
Properties
Level1.settings
Level2.settings
I am currently reading them with separate functions, for example:
void readLevel1()
{
levelMessage = Properties.Level1.Default.WelcomeMessage;
}
In this example, how could I pass "Level1" as a parameter to the function?
I would have preferred something like:
void readLevel(String identifier)
{
levelMessage = ConfigurationManager.AppSettings[identifier].Default.WelcomeMessage;
}
But I'm getting syntax errors on "Default" says, 'string does not contain a definition for 'Default' and not extension method 'Default' accepting a first argument of String can be found'. Any help would be greatly appreciated!
New Info:
OK I have been banging my head on the wall all day and here's what I came up with, that seems to work:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ConfigurationSection cs = config.SectionGroups["applicationSettings"].Sections["AppTitle.Properties.Level1"];
ClientSettingsSection css = (ClientSettingsSection)cs;
String s = css.Settings.Get("WelcomeMessage").Value.ValueXml.InnerText;
If anyone knows a better way please let me know! Using InnerText feels like a hack.
Thank you Ann for trying to help!
I am going to assume that Level1 and Level2 have all the same properties with all the same definitions.
In that case, you could create an interface that both Level1 and Level2 would implement. You could then define your settings-reading method like this:
void ReadLevel(ILevelSettings settingsInstance)
{
levelMessage = settingsInstance.WelcomeMessage;
}
You would call it like this:
ReadLevel(Properties.Level1.Default);
If the generated classes for Level1 and Level2 are partial classes (and I can't remember if they are) this should be easy to implement.
ETA: Partial class demonstration:
The partial keyword on a class definition means that the definition of the class is not necessarily all within one source code file. You can have others.
So you can create your own source code file, call it something like "Level1.partial.cs", and use this code:
namespace AppTitle.Properties
{
internal sealed partial class Level1 : ILevelSettings
{
// any additional functions or properties that you would like
// your Level1 class to have.
}
}
(Disclaimer: that was from memory. I omitted the using statements.)
At compile time, the compiler will gather up all the definitions of class Level1 that have the same namespace and modifying keywords (internal, sealed) and build them into a single class, mixing the generated methods and properties and any ones you added.
You can thereby make the generated Level1 and Level2 classes inherit from an interface (or even a base class), even though most of the class definition was generated. You can regenerate it at any time without affecting the code you added, because it's in a different file.
My problem is similar to this one, except that the code I want to use with protobuf-net was generated by the WSDL utility. "They tell me" that it's not appropriate to plan to modify the generated code (to add attributes).
It would be odd to write something to build a matching set of DTO classes, given that (other than the methods described) all the classes are already public (partial) classes marked with [Serializable] and have all public properties -- that is, they are very DTO-like already.
The simplest solution I've seen is to violate the rules and modify the code. If all strings in the generated C# file
public partial class
are replaced with
[ProtoBuf.ProtoContract(ImplicitFields = ProtoBuf.ImplicitFields.AllPublic)]
public partial class
from my limited testing that will do the trick. Does a better solution exist? Is there something wrong with using that technique (other than that I'm modifying generated code)?
Type-level attributes in partial classes can be added in separate code files. All you need is a separate file with just:
[ProtoBuf.ProtoContract(ImplicitFields = ProtoBuf.ImplicitFields.AllPublic)]
public partial class {}
it must also be in the right namespace, but you didn't say which, so probably:
namespace Foo {
[ProtoBuf.ProtoContract(ImplicitFields = ProtoBuf.ImplicitFields.AllPublic)]
public partial class {}
}
I am looking to create Extension classes that extend Entity Framework Entities in a different assembly to the EF Entities. I also want to code gen some additional/generic methods in an extension methods class (using T4), then have the ability to create a partial extension methods class with additional custom methods. Is this possible.
You don't need them. Just write another extension class.
namespace Namespace1
{
public static class MyEntityBlibblingExtensions
{
public void Blibble(this MyEntity self)
{
// ...
}
}
}
Then, elsewhere...
namespace Namespace2
{
public static class MyEntityFurtlingExtensions
{
public void Furtle(this MyEntity self)
{
// ...
}
}
}
Anything importing Namespace1 will see the extension method Blibble() while anything importing Namespace2 will see Furtle(), and importing both will see both. They can be in different assemblies or anywhere which imports MyEntity's namespace. So, partial extensions aren't really a valid concept. In fact, the very idea of putting extension methods inside classes is a bit of a hack as it is - a shame they couldn't unbend C#'s rules enough to let extension methods live outside of classes.
Yes - i tried it and it worked.
There is no such thing as an "extension" class - there are only extension methods which must be inside a "static" class.
You can have static partial classes.
UPDATE: Sorry I read your heading but not the text of your question.
The answer is still yes, but why not just create new classes? I can't see how having a partial class really helps in this case.
The main problem I can see here is the phrase "in a different assembly". If it wasn't for that, you could just add your methods etc in an additional partial class with regular instance methods, and it would all be fine.
You can have static partial classes, however you cannot use partial classes to add to a type in another assembly. Extension methods work fine from a partial class, although note that partial classes are purely a mechanism for splitting code between different files. You could just as easily have multiple static classes for the extension methods.
I used the OWLGrinder to create the assembly and imported the library into my project. That works fine. Now I want to write my own set of classes. Therefore I extended these with the equivalent of the assembly. But it just doesn't work.
The ontology holds a class named ManagementObject.
I created another Class (C#) called RealWorldObject:
public class RealWorldObject : ManagementObject
{
public RealWorldObject(string uri) : base(uri) { }
public RealWorldObject(string uri, RdfDocument rdfdocument) : base(uri, rdfdocument) { }
public RealWorldObject(RdfDocument rdfdocument) : base(rdfdocument) { }
public String getClassName()
{
return this.OwlClassName;
}
public static RdfDocument addRealWorldObjectIndividualt(RdfDocument rdfDocument)
{
Vehicle vehicle = new Vehicle("vehicle1", rdfDocument);
FixedEvent fxE1 = new FixedEvent("autoGekauft", rdfDocument);
fxE1.agent = new xmlns.com.foaf._01.Person("robert", rdfDocument);
vehicle.hasFixedEvent = fxE1;
return rdfDocument;
}
Which leads to the error:
ObjectManagement.Object.RealWorldObject does declare one (and only one) OwlClassAttribute. This is an implementation bug of the plugin.
How else should I extend the generated classes by the OWLGrinder.
Thx it is a long time ago that I used C#, so I'm kind of rusty.
The auto-generated classes produced by OwlGrinder.exe have not been designed for inheritance in mind. I am not saying it is wrong, it is just not designed for that. The auto-generated classes contain plenty of metadata defined as class attributes and inheritance hides all of that. The infrastructure counts on the presence of these attributes and if they are hidden, you get these runtime error messages.
Using Visual Studio Object Browser, take a look of the attributes over the auto-generated classes. OwlClassAttribute, SubClassOfAttribute, LightVersionAttribute are certainly mandatory. You may simply copy/paste the class attributes of ManagementObject on the top of your RealWorldObject class. I assume, it will work. But again, you might bump into additional show stoppers, as you do not follow the default routes ROWLEX has been designed for. This is a bit living on the edge :)
Instead of inheritance, you might consider reverse engineering your auto-generated assembly to C# using Reflector or other tools. Having the source code in your hand, you may modify the generated classes directly. You might make your ManagementObject class partial, and implement your additional methods in a separate file.