So I'm playing around with EnvDTE, and the EnvDTE.CodeModel API, And I was wondering if there was a way to get the text value represented by a CodeElement.
Let's say I have an CodeAttribute, is there some way to get a string of what the CodeAttribute represents, i.e.[MyAttribute(value="myvalue")].
I know it's possible to reconstruct the code using the various properties of the CodeElement, at least in some scenarios, but for some things it seems it would be easier to just get the text.
Thanks!
The CodeElement interface has the properties StartPoint and EndPoint which represent the start and end of the element within the buffer. These contain the Line Number / Column which can be passed to methods like IVsTextLines.GetLineText and give you back the value you're looking for.
To get the IVsTextLines for a given CodeElement you can do the following
CodeElement ce = ...;
TextDocument td = ce.StartPoint.Parent;
IVsTextLines lines = td as IVsTextLines;
void WriteMapping(CodeProperty codeProperty)
{
WriteLine("");
WriteLine("///CodeProperty");
WriteLine("///<summary>");
WriteLine("///"+codeProperty.FullName);
WriteLine("///</summary>");
if(codeProperty.Getter==null && codeProperty.Setter==null)
return;
if(codeProperty.Attributes!=null){
foreach(CodeAttribute a in codeProperty.Attributes)
{
Write("["+a.FullName);
if(a.Children!=null && a.Children.Count>0)
{
var start=a.Children.Cast<CodeElement>().First().GetStartPoint();
var finish= a.GetEndPoint();
string allArguments=start.CreateEditPoint().GetText(finish);
Write("("+allArguments);
}
WriteLine("]");
}
}
Write("public "+GetFullName(codeProperty.Type) +" "+codeProperty.Prototype);
Write(" {");
//if(codeProperty.Getter!=null && codeProperty.Getter.Access!=vsCMAccess.vsCMAccessPrivate)
Write("get;");
//if(codeProperty.Setter!=null)
Write("set;");
WriteLine("}");
}
In addition to the answer by #JaredPar, an alternative approach would be:
public string GetText(CodeAttribute attribute)
{
return attribute.StartPoint.CreateEditPoint().GetText(attribute.EndPoint);
}
That's it!! (Thanks #JaredPar for the pointers)
Source: http://msdn.microsoft.com/en-us/library/envdte.editpoint.gettext.aspx
Related
I am working in .cs file and I need to see the output of some object/variable executed by the c# program. I will use that for debbuging purposes each time.
For example, in the code below, I need to see the output of the variable DataNaiss (type,number of rows,all elements included...).
var DataNaiss = engine.Evaluate("DataNaiss=DataIns[which(cond1 & DataIns$Id %in% ID_Final),'Date.naissance']").AsCharacter();
I tried to Add this code :
Console.WriteLine(DataNaiss.ToString());
Console.ReadLine();
The output is in this picture :
Just see the end line please R.net CharacterVector . It seems that it talk about the type of DataNaiss But where are all elements of it?
In other way, until now I don't know why I have also in the same console window the data of the table DataAch imported knowing that I just call console window for showing DataNaiss and not for other thing !! you can see in the same picture elements of the first table DataAch.
my code of importing data is:
REngine engine = REngine.GetInstance();
DataFrame DataAch = engine.Evaluate("DataAch=read.table('C:/Users/isalah/Desktop/Fichiers_CRM/Fichier_csv/Achats1.csv',header=TRUE,sep =';',fill =TRUE)").AsDataFrame();
DataFrame DataDia = engine.Evaluate("DataDia=read.table('C:/Users/isalah/Desktop/Fichiers_CRM/Fichier_csv/Diagnostic.csv',header=TRUE,sep =';',fill=TRUE)").AsDataFrame();
DataFrame DataCad = engine.Evaluate("DataCad=read.table('C:/Users/isalah/Desktop/Fichiers_CRM/Fichier_csv/CADEAUX.csv',header=TRUE,sep =';',fill=TRUE)").AsDataFrame();
DataFrame DataIns = engine.Evaluate("DataIns=read.table('C:/Users/isalah/Desktop/Fichiers_CRM/Fichier_csv/Inscrits.csv',header=TRUE,sep =';',fill =TRUE)").AsDataFrame();
How do you explain this please?
Just see the end line please R.net CharacterVector . It seems that it talk about the type of DataNaiss But where are all elements of it?
Calling .ToString() on a variable won't magically show all the data you need.
According to Microsoft Documentation you can see that:
The default implementation of the ToString method returns the fully qualified name of the type of the Object
Therefor, you can understand that the type of that variable called DataNaiss in your case is actually of type CharacterVector.
Looking at the source code of R.Net you can obviously see that the class CharacterVector doesn't override ToString method.
In order to get the elements of the variable DataNaiss you have to access them yourself. The only way I can see from the source code is to access them like DataNaiss[0] since in their source code you have:
public override string this[int index]
{
get
{
if (index < 0 || Length <= index)
{
throw new ArgumentOutOfRangeException();
}
using (new ProtectedPointer(this))
{
return GetValue(index);
}
}
set
{
if (index < 0 || Length <= index)
{
throw new ArgumentOutOfRangeException();
}
using (new ProtectedPointer(this))
{
SetValue(index, value);
}
}
}
I suggest you can loop over the DataNaiss object according to it's length, and grab the data you need, for example if you have access to Length property:
for (int i=0; i<DataNaiss.Length; i++)
{
Console.WriteLine(DataNaiss[i]);
}
This is not tested. I am answering all of this according to what I read in their code.
By overriding the ToString Function on the Types in the DataNaiss variable you can print them to the Console.
Following the MSDN Guide you do can do this like this:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return "Person: " + Name + " " + Age;
}
}
By then calling ToString() on the objects allows you to print them.
I have the following enum declared:
public enum EtcMethod
{
ACCORD,
COROLLA,
COROLLA_S,
CAMRY,
CIVIC
}
On my form, I have a handful of controls with their Tag property set:
myControl1.Tag = "ACCORD";
myControl2.Tag = "COROLLA";
myControl3.Tag = "CIVIC COROLLA_S CAMRY";
Then I'm checking the controls' tags in a loop to see if any of the values are found:
private void HideControls(EtcMethod etcMethod, LayoutControlGroup lcg)
{
foreach (BaseLayoutItem ctl in lcg.Items)
{
if (ctl.GetType() == typeof (LayoutControlItem))
{
LayoutControlItem item = (LayoutControlItem)ctl;
if (item.Tag.ToString().IndexOf(etcMethod.ToString()) >= 0)
item.Visibility = LayoutVisibility.Always;
else
item.Visibility = LayoutVisibility.Never;
}
}
}
But the problem with this is, for example, if etcMethod is COROLLA and item.Tag.ToString() is "COROLLA_S" that'll erroneously pass the check.
How can I make sure that it'll find an exact match instead of a "partial" match? In other words, I would like it to behave as if you checked off the "Match whole word" option using Visual Studio's Find feature.
The only solution I could think of would be to check the value of the character at etcMethod.Lenght+1 and see if it's a space (indicating the beginning of another enum value) or if that position even exists (indicating the end of the tag), but that seems particularly sloppy.
Why don't you Split it and use Contains ?
if (item.Tag.ToString().Split().Contains(etcMethod.ToString()))
This will first split your Tag on space, if it hasn't space it just turn it into a string array, then using Contains on array will look for exact match.
This may be one solution:
if (item.Tag.ToString() + " ").IndexOf(etcMethod.ToString() + " ") >= 0)
Note: I've read this and its not quite what I'm looking for:
I have an app that builds up XML from an input file and creates one of two outputs, depending upon the file chosen. It was a "quick n dirty" app to get round an immediate problem, but I know it's going to find further use and want to pre-empt this by refactoring.
At the moment I have a "builder" class that takes the input (in its ctor) and exposes a property which is the required XElement. However, many of the XElements are identical, except for the content, for both of my XML outputs. (Oh, please ignore the validation part which I'll refactor separately)
So I'm looking at a sensible way of DRYing my app:
At the moment I have something like this.
public FirstBuilder(string line, int lineNumber, bool output, string subjectType, string inquiryCode)
{
var split = Regex.Split(line, #"\|");
if (split.Count() != SPLIT_COUNT)
throw new Exception("This does not appear to be a valid First Type input file.");
_lineNumber = lineNumber;
_reportId = output ? TXT_REPORT_ID : XML_REPORT_ID;
_subjectType = subjectType;
_responseType = output ? TXT_RESPONSE_TYPE : XML_REPONSE_TYPE;
_inquiryCode = inquiryCode;
_product = split[0];
_number = split[1];
_amount = split[2];
_currency = split[3];
_name = split[4];
_nationalId = split[5];
_gender = split[6];
_dateOfBirth = split[7];
_nationality = split[8];
}
public XElement RequestElement
{
get
{
return new XElement("REQUEST",
new XAttribute("REQUEST_ID", _lineNumber),
RequestParametersElement,
SearchParametersElement);
}
}
private XElement RequestParametersElement
{
get
{
return new XElement("REQUEST_PARAMETERS",
ReportParametersElement,
InquiryPurposeElement,
ApplicationElement);
}
}
private XElement ReportParametersElement
{
get
{
return new XElement("REPORT_PARAMETERS",
new XAttribute("REPORT_ID", _reportId),
new XAttribute("SUBJECT_TYPE", _subjectType),
new XAttribute("RESPONSE_TYPE", _responseType));
}
}
etc. etc...
//used by
var x = new FirstBuilder(x,y,z,etc.).RequestElement();
This all works and is very fast...but SecondBuilder also uses these same elements, along with some different ones.
So I'm looking at the "best" way to refactor these out:
Shared Abstract class with inheritance?
Shared "Helper" classes?
Extension methods to return "built" elements?
Classes per element that extend XElement?
My suspicion is that this will balloon from the two examples as a quick solution to around 30 in then next month!
THX.
I would refactor the private properties to methods that receive the required values as input parameters. You can then move them into a PartsBuilder class and use that one in you concrete builders.
I have strings of eight characters like below. The presence of zeros in the last column identifies these as type pr, pa, fo or it records:
01020304
01020300
01020000
01000000
I already coded the following but it looks clumsy to me.
if ( id.Substring(2) == "000000") {
// pr record
} else if ( id.Substring(4) == "0000") {
// pa record
} else if ( id.Substring(6) == "00") {
// fo record
} else {
// it record
}
Can anyone think of a cleaner way to code this?
Not massively different to what you've got, just a bit more readable IMO.
const string PR = "000000";
const string PA = "0000";
const string FO = "00";
if (id.EndsWith(PR))
{
// pr record
}
else if(id.EndsWith(PA))
{
// pa record
}
else if (id.EndsWith(FO))
{
// fo record
}
else
{
// it record
}
By value.TrimEnd('0').Length ?
Nothing wrong with testing the strings, however:
substring probably produces a new string object
is there no endswith in C#?
it is fairly easy to write function that counts the number of trailing zeros. Then you could do a switch(trailingZeros(id)) { case 0: ... }
You may want to take a look at the Filehelpers library -- it's got all sorts of infrastructure to read and process records, including a way to determine different record types -- see "Multirecords".
Note: the main Filehelpers website is based on the 2.0 release of this library. A newer version exists in a public repository. In either case, I'd recommend grabbing the source code for the library, as I haven't seen a ton of activity in terms of new development for this library.
We have some stuff that may be exported into various formats. Currently we have these formats represented by an enum like this:
[Flags]
public enum ExportFormat
{
None = 0x0,
Csv = 0x1,
Tsv = 0x2,
Excel = 0x4,
All = Excel | Csv | Tsv
}
Problem is that these must be enumerated and they also need a translation or description in the ui. Currently I solved this by creating two extension methods. They work, but I don't really like them or the solution at all... they feel kind of smelly. Problem is I don't really know how I could do this better. Does anyone have any good alternatives? These are the two methods:
public static IEnumerable<ExportFormat> Formats(this ExportFormat exportFormats)
{
foreach (ExportFormat e in Enum.GetValues(typeof (ExportFormat)))
{
if (e == ExportFormat.None || e == ExportFormat.All)
continue;
if ((exportFormats & e) == e)
yield return e;
}
}
public static string Describe(this ExportFormat e)
{
var r = new List<string>();
if ((e & ExportFormat.Csv) == ExportFormat.Csv)
r.Add("Comma Separated Values");
if ((e & ExportFormat.Tsv) == ExportFormat.Tsv)
r.Add("Tab Separated Values");
if ((e & ExportFormat.Excel) == ExportFormat.Excel)
r.Add("Microsoft Excel 2007");
return r.Join(", ");
}
Maybe this is the way to do this, but I have a feeling there must be better ways to do it. How could I refactor this?
You could use the Formats method inside Describe to avoid doing all the bit operations at multiple places, like this:
private static Dictionary<ExportFormat, string> FormatDescriptions =
new Dictionary<ExportFormat,string>()
{
{ ExportFormat.Csv, "Comma Separated Values" },
{ ExportFormat.Tsv, "Tab Separated Values" },
{ ExportFormat.Excel, "Microsoft Excel 2007" },
};
public static string Describe(this ExportFormat e)
{
var formats = e.Formats();
var descriptions = formats.Select(fmt => FormatDescriptions[fmt]);
return string.Join(", ", descriptions.ToArray());
}
This way, it is easy to incorporate the string descriptions from an external source or localization, as hinted above.
The only other way comes to my mind is the usage of the System.Attribute class.
public class FormatDescription : Attribute
{
public string Description { get; private set; }
public FormatDescription(string description)
{
Description = description;
}
}
And then use Reflection with in your Describe function.
The only benefit of this method would be to have definition and the description at one place.
Dupe: How do I have an enum bound combobox with custom string formatting for enum values?
You could write an TypeConverter that reads specified attributes to look them up in your resources. Thus you would get multi-language support for display names without much hastle.
Look into the TypeConverter's ConvertFrom/ConvertTo methods, and use reflection to read attributes on your enum fields.
Addition:
Scroll down in the linked post for a implementation of a TypeConverter that does part of what is required for full support.
This would support an application where you have several languages at the same time, not only code name -> english name.
Remember that this is only the display name, never the stored value. You should always store the code name, or the integer value, to support users with different locales using the same data.