├── .gitattributes
├── .gitignore
├── AOPViaT4Examples.sln
├── App
├── App.config
├── App.csproj
├── LoggingAspectLocal.cs
├── LoggingAspectLocal.tt
├── Program.cs
├── Properties
│ └── AssemblyInfo.cs
├── RetryAspectLocal.cs
└── RetryAspectLocal.tt
├── Library
├── Document.cs
├── DocumentSource.cs
├── IDocumentSource.cs
├── Library.csproj
└── Properties
│ └── AssemblyInfo.cs
├── Logging
├── ConsoleLogger.cs
├── ILogger.cs
├── Logging.csproj
├── LoggingData.cs
└── Properties
│ └── AssemblyInfo.cs
├── LoggingAOP
├── LogAttribute.cs
├── LogCountAttribute.cs
├── LoggingAOP.csproj
├── MethodDescriptionAttribute.cs
└── Properties
│ └── AssemblyInfo.cs
├── README.md
└── T4Aspects
├── CompositePostInvocationLoggingDataCodeGenerator.tt
├── CompositePreInvocationLoggingDataCodeGenerator.tt
├── LoggingAspect.Core.tt
├── LoggingAspect.tt
├── LoggingDataCodeGeneratorForArgumentsBasedOnTheLogAttribute.tt
├── LoggingDataCodeGeneratorForArgumentsBasedOnTheLogCountAttribute.tt
├── LoggingDataCodeGeneratorForReturnValueBasedOnTheLogAttribute.tt
├── LoggingDataCodeGeneratorForReturnValueBasedOnTheLogCountAttribute.tt
├── MethodDescriptionLoggingDataCodeGenerator.tt
├── Properties
└── AssemblyInfo.cs
├── RetryAspect.tt
├── T4Aspects.csproj
└── Utilities
├── AttributeValueExtractor.tt
├── ClassFinder.tt
├── InterfaceFinder.tt
├── MethodMatcher.tt
└── MethodParametersGenerator.tt
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.cs eol=crlf
2 | *.tt eol=crlf
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
--------------------------------------------------------------------------------
/AOPViaT4Examples.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library", "Library\Library.csproj", "{4336620E-9849-40D4-9E90-FD449E8CE83C}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LoggingAOP", "LoggingAOP\LoggingAOP.csproj", "{25F930E2-3F2D-4B06-9545-9E03EB59B11C}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "T4Aspects", "T4Aspects\T4Aspects.csproj", "{24148B11-2079-440A-A7D2-1DBDC0848855}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logging", "Logging\Logging.csproj", "{B4FD511B-81D5-4B28-9D4F-7C3B5CFFEC5D}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "App\App.csproj", "{87F51EEA-92F9-4A86-B004-C6EA5CBDE48C}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Release|Any CPU = Release|Any CPU
20 | EndGlobalSection
21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
22 | {4336620E-9849-40D4-9E90-FD449E8CE83C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {4336620E-9849-40D4-9E90-FD449E8CE83C}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {4336620E-9849-40D4-9E90-FD449E8CE83C}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {4336620E-9849-40D4-9E90-FD449E8CE83C}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {25F930E2-3F2D-4B06-9545-9E03EB59B11C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {25F930E2-3F2D-4B06-9545-9E03EB59B11C}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {25F930E2-3F2D-4B06-9545-9E03EB59B11C}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {25F930E2-3F2D-4B06-9545-9E03EB59B11C}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {24148B11-2079-440A-A7D2-1DBDC0848855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {24148B11-2079-440A-A7D2-1DBDC0848855}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {24148B11-2079-440A-A7D2-1DBDC0848855}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {24148B11-2079-440A-A7D2-1DBDC0848855}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {B4FD511B-81D5-4B28-9D4F-7C3B5CFFEC5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {B4FD511B-81D5-4B28-9D4F-7C3B5CFFEC5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {B4FD511B-81D5-4B28-9D4F-7C3B5CFFEC5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {B4FD511B-81D5-4B28-9D4F-7C3B5CFFEC5D}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {87F51EEA-92F9-4A86-B004-C6EA5CBDE48C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {87F51EEA-92F9-4A86-B004-C6EA5CBDE48C}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {87F51EEA-92F9-4A86-B004-C6EA5CBDE48C}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {87F51EEA-92F9-4A86-B004-C6EA5CBDE48C}.Release|Any CPU.Build.0 = Release|Any CPU
42 | EndGlobalSection
43 | GlobalSection(SolutionProperties) = preSolution
44 | HideSolutionNode = FALSE
45 | EndGlobalSection
46 | EndGlobal
47 |
--------------------------------------------------------------------------------
/App/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/App/App.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {87F51EEA-92F9-4A86-B004-C6EA5CBDE48C}
8 | Exe
9 | Properties
10 | App
11 | App
12 | v4.5.2
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | True
48 | True
49 | LoggingAspectLocal.tt
50 |
51 |
52 |
53 |
54 | True
55 | True
56 | RetryAspectLocal.tt
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | TextTemplatingFileGenerator
65 | LoggingAspectLocal.cs
66 |
67 |
68 | TextTemplatingFileGenerator
69 | RetryAspectLocal.cs
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | {4336620e-9849-40d4-9e90-fd449e8ce83c}
78 | Library
79 |
80 |
81 | {b4fd511b-81d5-4b28-9d4f-7c3b5cffec5d}
82 | Logging
83 |
84 |
85 |
86 |
93 |
--------------------------------------------------------------------------------
/App/LoggingAspectLocal.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Library
3 | {
4 | using System;
5 | using Logging;
6 | using System.Linq;
7 |
8 | public class DocumentSourceLoggingDecorator : Library.IDocumentSource
9 | {
10 | private readonly Library.DocumentSource decorated;
11 | private readonly ILogger logger;
12 | private readonly LoggingData[] constantLoggingData;
13 |
14 | public DocumentSourceLoggingDecorator(Library.DocumentSource decorated, ILogger logger, params LoggingData[] constantLoggingData)
15 | {
16 | this.decorated = decorated;
17 | this.logger = logger;
18 | this.constantLoggingData = constantLoggingData;
19 | }
20 |
21 | public Library.Document[] GetDocuments(System.String format)
22 | {
23 | var preInvocationLoggingData =
24 | new LoggingData[]
25 | {
26 | new LoggingData{ Name = "Method", Value = "Get Documents"},
27 | new LoggingData{ Name = "Document Format", Value = format},
28 | }
29 | .Concat(constantLoggingData)
30 | .ToArray();
31 |
32 | Library.Document[] returnValue;
33 |
34 | try
35 | {
36 | returnValue = decorated.GetDocuments(format);
37 | }
38 | catch(Exception ex)
39 | {
40 | logger.LogError(preInvocationLoggingData, ex);
41 | throw;
42 | }
43 |
44 | var returnValueLoggingData = new LoggingData[]
45 | {
46 | new LoggingData{ Name = "Return Value", Value = returnValue.Length.ToString()},
47 | };
48 |
49 | logger.LogSuccess(preInvocationLoggingData.Concat(returnValueLoggingData).ToArray());
50 |
51 | return returnValue;
52 |
53 | }
54 |
55 | }
56 |
57 | public static class DocumentSourceExtensionMethodsForLoggingAspect
58 | {
59 | public static Library.IDocumentSource AsLoggable(this Library.DocumentSource instance, ILogger logger, params LoggingData[] constantLoggingData)
60 | {
61 | return new DocumentSourceLoggingDecorator(instance, logger, constantLoggingData);
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/App/LoggingAspectLocal.tt:
--------------------------------------------------------------------------------
1 | <#@ template debug="false" hostspecific="true" language="C#" #>
2 | <#@ assembly name="EnvDTE" #>
3 | <#@ import namespace="EnvDTE" #>
4 | <#@ include file="$(SolutionDir)T4Aspects\LoggingAspect.tt" #><##>
5 | <#@ include file="$(SolutionDir)T4Aspects\LoggingDataCodeGeneratorForArgumentsBasedOnTheLogAttribute.tt" #><##>
6 | <#@ include file="$(SolutionDir)T4Aspects\LoggingDataCodeGeneratorForArgumentsBasedOnTheLogCountAttribute.tt" #><##>
7 | <#@ include file="$(SolutionDir)T4Aspects\LoggingDataCodeGeneratorForReturnValueBasedOnTheLogAttribute.tt" #><##>
8 | <#@ include file="$(SolutionDir)T4Aspects\LoggingDataCodeGeneratorForReturnValueBasedOnTheLogCountAttribute.tt" #><##>
9 | <#@ include file="$(SolutionDir)T4Aspects\CompositePostInvocationLoggingDataCodeGenerator.tt" #><##>
10 | <#@ include file="$(SolutionDir)T4Aspects\CompositePreInvocationLoggingDataCodeGenerator.tt" #><##>
11 | <#@ include file="$(SolutionDir)T4Aspects\MethodDescriptionLoggingDataCodeGenerator.tt" #><##>
12 | <#@include once="true" file="$(SolutionDir)T4Aspects\LoggingAspect.Core.tt"#><##>
13 | <#@include once="true" file="$(SolutionDir)T4Aspects\Utilities\ClassFinder.tt"#><##>
14 | <#@ output extension="cs"#><##>
15 | <#
16 | var hostServiceProvider = (IServiceProvider) Host;
17 | var dte = (DTE) hostServiceProvider.GetService(typeof(DTE));
18 |
19 | var classes = ClassFinder.FindClassesInSolution(dte, new[] {"DocumentSource"});
20 |
21 | foreach (var @class in classes)
22 | {
23 | GenerateLoggingDecoratorForClass(
24 | @class,
25 | @class.ImplementedInterfaces.Cast().Single(),
26 | new CompositePreInvocationLoggingDataCodeGenerator(
27 | new MethodDescriptionLoggingDataCodeGenerator(),
28 | new LoggingDataCodeGeneratorForArgumentsBasedOnTheLogAttribute(),
29 | new LoggingDataCodeGeneratorForArgumentsBasedOnTheLogCountAttribute()),
30 | new CompositePostInvocationLoggingDataCodeGenerator(
31 | new LoggingDataCodeGeneratorForReturnValueBasedOnTheLogAttribute(),
32 | new LoggingDataCodeGeneratorForReturnValueBasedOnTheLogCountAttribute()));
33 | }
34 | #>
--------------------------------------------------------------------------------
/App/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Library;
7 | using Logging;
8 |
9 | namespace App
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | var documentSource =
16 | new DocumentSource()
17 | .AsLoggable(
18 | new ConsoleLogger(),
19 | new LoggingData { Name = "Department", Value = "A" })
20 | .ApplyRetryAspect(
21 | numberOfRetries: 3,
22 | waitTimeBetweenRetries: TimeSpan.FromSeconds(5));
23 |
24 | var result = documentSource.GetDocuments("docx");
25 |
26 | Console.ReadLine();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/App/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("App")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("App")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("87f51eea-92f9-4a86-b004-c6ea5cbde48c")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/App/RetryAspectLocal.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Library
3 | {
4 | using System;
5 | using System.Threading;
6 |
7 | public class DocumentSourceRetryDecorator : Library.IDocumentSource
8 | {
9 | private readonly Library.IDocumentSource decorated;
10 | private readonly int numberOfRetries;
11 | private readonly TimeSpan waitTimeBetweenRetries;
12 |
13 | public DocumentSourceRetryDecorator(
14 | Library.IDocumentSource decorated,
15 | int numberOfRetries,
16 | TimeSpan waitTimeBetweenRetries)
17 | {
18 | this.decorated = decorated;
19 | this.numberOfRetries = numberOfRetries;
20 | this.waitTimeBetweenRetries = waitTimeBetweenRetries;
21 | }
22 |
23 | public Library.Document[] GetDocuments(System.String format)
24 | {
25 | int retries = 0;
26 |
27 | while(true)
28 | {
29 | try
30 | {
31 | return decorated.GetDocuments(format);
32 | }
33 | catch
34 | {
35 | retries++;
36 |
37 | if(retries == numberOfRetries)
38 | throw;
39 |
40 | Thread.Sleep(waitTimeBetweenRetries);
41 | }
42 | }
43 | }
44 |
45 | }
46 |
47 | public static class ExtensionMethodsForRetryAspectForDocumentSource
48 | {
49 | public static Library.IDocumentSource ApplyRetryAspect(this Library.IDocumentSource instance, int numberOfRetries, TimeSpan waitTimeBetweenRetries)
50 | {
51 | return new DocumentSourceRetryDecorator(instance, numberOfRetries, waitTimeBetweenRetries);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/App/RetryAspectLocal.tt:
--------------------------------------------------------------------------------
1 | <#@ template debug="false" hostspecific="true" language="C#" #>
2 | <#@ assembly name="EnvDTE" #>
3 | <#@ import namespace="EnvDTE" #>
4 | <#@include once="true" file="$(SolutionDir)T4Aspects\RetryAspect.tt"#><##>
5 | <#@include once="true" file="$(SolutionDir)T4Aspects\Utilities\InterfaceFinder.tt"#><##>
6 | <#@ output extension="cs"#>
7 | <#
8 | var hostServiceProvider = (IServiceProvider) Host;
9 | var dte = (DTE) hostServiceProvider.GetService(typeof(DTE));
10 |
11 | var interfaces = InterfaceFinder.FindInterfacesInSolution(dte, new[] {"IDocumentSource"});
12 |
13 | foreach (var @interface in interfaces)
14 | {
15 | GenerateRetryDecoratorForInterface(@interface);
16 | }
17 | #>
--------------------------------------------------------------------------------
/Library/Document.cs:
--------------------------------------------------------------------------------
1 | namespace Library
2 | {
3 | public class Document
4 | {
5 | public Document(string name, string content)
6 | {
7 | Name = name;
8 | Content = content;
9 | }
10 |
11 | public string Name { get; private set; }
12 | public string Content { get; private set; }
13 | }
14 | }
--------------------------------------------------------------------------------
/Library/DocumentSource.cs:
--------------------------------------------------------------------------------
1 | using System.Linq;
2 | using LoggingAOP;
3 |
4 | namespace Library
5 | {
6 | public class DocumentSource : IDocumentSource
7 | {
8 | [return: LogCount]
9 | [MethodDescription("Get Documents")]
10 | public Document[] GetDocuments([Log("Document Format")] string format)
11 | {
12 | return
13 | Enumerable
14 | .Range(0, 10)
15 | .Select(x => new Document("document" + x, "content" + x))
16 | .ToArray();
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Library/IDocumentSource.cs:
--------------------------------------------------------------------------------
1 | namespace Library
2 | {
3 | public interface IDocumentSource
4 | {
5 | Document[] GetDocuments(string format);
6 | }
7 | }
--------------------------------------------------------------------------------
/Library/Library.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {4336620E-9849-40D4-9E90-FD449E8CE83C}
8 | Library
9 | Properties
10 | Library
11 | Library
12 | v4.5.2
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | {25F930E2-3F2D-4B06-9545-9E03EB59B11C}
51 | LoggingAOP
52 |
53 |
54 |
55 |
62 |
--------------------------------------------------------------------------------
/Library/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Library")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Library")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("4336620e-9849-40d4-9e90-fd449e8ce83c")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Logging/ConsoleLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Logging
8 | {
9 | public class ConsoleLogger : ILogger
10 | {
11 | public void LogSuccess(LoggingData[] loggingData)
12 | {
13 | Console.WriteLine("Success" + Environment.NewLine + FormatLoggingData(loggingData));
14 | }
15 |
16 | public void LogError(LoggingData[] loggingData, Exception exception)
17 | {
18 | Console.WriteLine("Error" + Environment.NewLine + FormatLoggingData(loggingData));
19 | Console.WriteLine(exception.Message);
20 | }
21 |
22 | private string FormatLoggingData(LoggingData[] loggingData)
23 | {
24 | StringBuilder sb = new StringBuilder();
25 |
26 | foreach (var item in loggingData)
27 | {
28 | sb.AppendLine(item.Name + ": " + item.Value);
29 | }
30 |
31 | return sb.ToString();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Logging/ILogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Logging
4 | {
5 | public interface ILogger
6 | {
7 | void LogSuccess(LoggingData[] loggingData);
8 | void LogError(LoggingData[] loggingData, Exception exception);
9 | }
10 | }
--------------------------------------------------------------------------------
/Logging/Logging.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {B4FD511B-81D5-4B28-9D4F-7C3B5CFFEC5D}
8 | Library
9 | Properties
10 | Logging
11 | Logging
12 | v4.5.2
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
56 |
--------------------------------------------------------------------------------
/Logging/LoggingData.cs:
--------------------------------------------------------------------------------
1 | namespace Logging
2 | {
3 | public class LoggingData
4 | {
5 | public string Name { get; set; }
6 | public string Value { get; set; }
7 | }
8 | }
--------------------------------------------------------------------------------
/Logging/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Logging")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Logging")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("b4fd511b-81d5-4b28-9d4f-7c3b5cffec5d")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/LoggingAOP/LogAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LoggingAOP
4 | {
5 | public class LogAttribute : Attribute
6 | {
7 | public LogAttribute(string name)
8 | {
9 | Name = name;
10 | }
11 |
12 | public LogAttribute()
13 | {
14 | }
15 |
16 | public string Name { get; private set; }
17 | }
18 | }
--------------------------------------------------------------------------------
/LoggingAOP/LogCountAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LoggingAOP
4 | {
5 | public class LogCountAttribute : Attribute
6 | {
7 | public LogCountAttribute(string name)
8 | {
9 | Name = name;
10 | }
11 |
12 | public LogCountAttribute()
13 | {
14 | }
15 |
16 | public string Name { get; private set; }
17 | }
18 | }
--------------------------------------------------------------------------------
/LoggingAOP/LoggingAOP.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {25F930E2-3F2D-4B06-9545-9E03EB59B11C}
8 | Library
9 | Properties
10 | LoggingAOP
11 | LoggingAOP
12 | v4.5.2
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
56 |
--------------------------------------------------------------------------------
/LoggingAOP/MethodDescriptionAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LoggingAOP
4 | {
5 | public class MethodDescriptionAttribute : Attribute
6 | {
7 | public string Description { get; private set; }
8 |
9 | public MethodDescriptionAttribute(string description)
10 | {
11 | Description = description;
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/LoggingAOP/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("LoggingAOP")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("LoggingAOP")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("25f930e2-3f2d-4b06-9545-9e03eb59b11c")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AOPViaT4Examples
2 |
3 | The code in this repository is an example to support the Aspect Oriented Programming (AOP) in C# via T4 article. You can read the article here: http://www.dotnetcurry.com/patterns-practices/1318/aspect-oriented-programming-aop-t4
4 |
--------------------------------------------------------------------------------
/T4Aspects/CompositePostInvocationLoggingDataCodeGenerator.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="System.Core" #>
3 | <#@ import namespace="EnvDTE" #>
4 | <#@ import namespace="System.Linq" #>
5 | <#@ include once="true" file="LoggingAspect.Core.tt"#><##>
6 | <#+
7 | public class CompositePostInvocationLoggingDataCodeGenerator : IPostInvocationLoggingDataCodeGenerator
8 | {
9 | private readonly IPostInvocationLoggingDataCodeGenerator[] generators;
10 |
11 | public CompositePostInvocationLoggingDataCodeGenerator(params IPostInvocationLoggingDataCodeGenerator[] generators)
12 | {
13 | this.generators = generators;
14 | }
15 |
16 | public LoggingDataCode[] Extract(CodeFunction method, string returnValueVariableName)
17 | {
18 | return generators.SelectMany(x => x.Extract(method, returnValueVariableName)).ToArray();
19 | }
20 | }
21 | #>
--------------------------------------------------------------------------------
/T4Aspects/CompositePreInvocationLoggingDataCodeGenerator.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="System.Core" #>
3 | <#@ import namespace="EnvDTE" #>
4 | <#@ import namespace="System.Linq" #>
5 | <#@ include once="true" file="LoggingAspect.Core.tt"#><##>
6 | <#+
7 | public class CompositePreInvocationLoggingDataCodeGenerator : IPreInvocationLoggingDataCodeGenerator
8 | {
9 | private readonly IPreInvocationLoggingDataCodeGenerator[] generators;
10 |
11 | public CompositePreInvocationLoggingDataCodeGenerator(params IPreInvocationLoggingDataCodeGenerator[] generators)
12 | {
13 | this.generators = generators;
14 | }
15 |
16 | public LoggingDataCode[] Extract(CodeFunction method)
17 | {
18 | return generators.SelectMany(x => x.Extract(method)).ToArray();
19 | }
20 | }
21 | #>
--------------------------------------------------------------------------------
/T4Aspects/LoggingAspect.Core.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="System.Core" #>
3 | <#@ import namespace="EnvDTE" #>
4 | <#@ import namespace="System.Linq" #>
5 | <#+
6 | public class LoggingDataCode
7 | {
8 | public LoggingDataCode(string nameCode, string valueCode)
9 | {
10 | NameCode = nameCode;
11 | ValueCode = valueCode;
12 | }
13 |
14 | public string NameCode { get;private set; }
15 |
16 | public string ValueCode { get; private set; }
17 | }
18 |
19 | public interface IPreInvocationLoggingDataCodeGenerator
20 | {
21 | LoggingDataCode[] Extract(CodeFunction method);
22 | }
23 |
24 | public interface IPostInvocationLoggingDataCodeGenerator
25 | {
26 | LoggingDataCode[] Extract(CodeFunction method, string returnValueVariableName);
27 | }
28 | #>
--------------------------------------------------------------------------------
/T4Aspects/LoggingAspect.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="EnvDTE80" #>
3 | <#@ assembly name="System.Core" #>
4 | <#@ import namespace="EnvDTE" #>
5 | <#@ import namespace="EnvDTE80" #>
6 | <#@ import namespace="System.Text" #>
7 | <#@ import namespace="System.Linq" #>
8 | <#@ include once="true" file="LoggingAspect.Core.tt"#><##>
9 | <#@ include once="true" file="Utilities\MethodParametersGenerator.tt"#><##>
10 | <#@ include once="true" file="Utilities\MethodMatcher.tt"#><##>
11 | <#+
12 | public void GenerateLoggingDecoratorForClass(
13 | CodeClass2 @class,
14 | CodeInterface @interface,
15 | IPreInvocationLoggingDataCodeGenerator preInvocationLoggingDataCodeExtractor,
16 | IPostInvocationLoggingDataCodeGenerator postInvocationLoggingDataCodeExtractor)
17 | {
18 |
19 | string className = @class.Name;
20 | string fullClassName = @class.FullName;
21 | string fullInterfaceName = @interface.FullName;
22 |
23 | string decoratorClassName = className + "LoggingDecorator";
24 |
25 | var @namespace = @class.Namespace.FullName;
26 |
27 | #>
28 |
29 | namespace <#= @namespace #>
30 | {
31 | using System;
32 | using Logging;
33 | using System.Linq;
34 |
35 | public class <#=decoratorClassName#> : <#=fullInterfaceName#>
36 | {
37 | private readonly <#=fullClassName#> decorated;
38 | private readonly ILogger logger;
39 | private readonly LoggingData[] constantLoggingData;
40 |
41 | public <#=decoratorClassName#>(<#=fullClassName#> decorated, ILogger logger, params LoggingData[] constantLoggingData)
42 | {
43 | this.decorated = decorated;
44 | this.logger = logger;
45 | this.constantLoggingData = constantLoggingData;
46 | }
47 |
48 | <#+
49 | PushIndent(new string(' ', 8));
50 | GenerateMethodsForClass(@class, @interface, preInvocationLoggingDataCodeExtractor, postInvocationLoggingDataCodeExtractor);
51 | PopIndent();
52 | #>
53 | }
54 |
55 | public static class <#=className#>ExtensionMethodsForLoggingAspect
56 | {
57 | public static <#=fullInterfaceName#> AsLoggable(this <#=fullClassName#> instance, ILogger logger, params LoggingData[] constantLoggingData)
58 | {
59 | return new <#=decoratorClassName#>(instance, logger, constantLoggingData);
60 | }
61 | }
62 | }
63 | <#+
64 | }
65 |
66 | public void GenerateMethodsForClass(
67 | CodeClass2 @class,
68 | CodeInterface @interface,
69 | IPreInvocationLoggingDataCodeGenerator preInvocationLoggingDataCodeExtractor,
70 | IPostInvocationLoggingDataCodeGenerator postInvocationLoggingDataCodeExtractor)
71 | {
72 |
73 |
74 | foreach (CodeFunction interfaceMethod in @interface.Members.OfType())
75 | {
76 |
77 | string methodReturnType =
78 | interfaceMethod.Type.TypeKind == vsCMTypeRef.vsCMTypeRefVoid
79 | ? "void"
80 | : interfaceMethod.Type.AsFullName;
81 |
82 | string methodName = interfaceMethod.Name;
83 | bool isVoid = interfaceMethod.Type.TypeKind == vsCMTypeRef.vsCMTypeRefVoid;
84 |
85 | var classMethod = MethodMatcher.GetClassMethodFromInterfaceMethod(interfaceMethod, @class);
86 |
87 |
88 | var preInvocationLoggingDataCodeList = preInvocationLoggingDataCodeExtractor.Extract(classMethod);
89 |
90 | var postInvocationLoggingDataCodeList = postInvocationLoggingDataCodeExtractor.Extract(classMethod, "returnValue");
91 |
92 | #>
93 | public <#=methodReturnType#> <#=methodName#>(<#=MethodParameterGenerator.GenerateMethodParametersWithTypes(classMethod)#>)
94 | {
95 | var preInvocationLoggingData =
96 | new LoggingData[]
97 | {
98 | <#+
99 | foreach (var loggingDataCode in preInvocationLoggingDataCodeList)
100 | {
101 | PushIndent(new string(' ', 8));
102 | RenderLoggingDataCode(loggingDataCode);
103 | PopIndent();
104 | }
105 | #>
106 | }
107 | .Concat(constantLoggingData)
108 | .ToArray();
109 |
110 | <#+
111 | if (!isVoid)
112 | {
113 | #>
114 | <#=methodReturnType#> returnValue;
115 |
116 | <#+
117 | }
118 | #>
119 | try
120 | {
121 | <#+
122 | if (isVoid)
123 | {
124 | #>
125 | decorated.<#=methodName #>(<#=MethodParameterGenerator.GenerateMethodParametersWithoutTypes(classMethod) #>);
126 | <#+
127 | }
128 | else
129 | {
130 | #>
131 | returnValue = decorated.<#=methodName #>(<#=MethodParameterGenerator.GenerateMethodParametersWithoutTypes(classMethod) #>);
132 | <#+
133 | }
134 | #>
135 | }
136 | catch(Exception ex)
137 | {
138 | logger.LogError(preInvocationLoggingData, ex);
139 | throw;
140 | }
141 | <#+
142 | if (!isVoid)
143 | {
144 | if (postInvocationLoggingDataCodeList.Length > 0)
145 | {
146 | #>
147 |
148 | var returnValueLoggingData = new LoggingData[]
149 | {
150 | <#+
151 | foreach (var loggingDataCode in postInvocationLoggingDataCodeList)
152 | {
153 | RenderLoggingDataCode(loggingDataCode);
154 | }
155 | #>
156 | };
157 |
158 | logger.LogSuccess(preInvocationLoggingData.Concat(returnValueLoggingData).ToArray());
159 | <#+
160 | }
161 | else
162 | {
163 | #>
164 |
165 | logger.LogSuccess(preInvocationLoggingData);
166 | <#+
167 | }
168 | #>
169 |
170 | return returnValue;
171 | <#+
172 | }
173 | else
174 | {
175 | #>
176 |
177 | logger.LogSuccess(preInvocationLoggingData);
178 | <#+
179 | }
180 | #>
181 |
182 | }
183 |
184 | <#+
185 | }
186 | }
187 |
188 | public void RenderLoggingDataCode(LoggingDataCode loggingDataCode)
189 | {
190 | #>
191 | new LoggingData{ Name = <#=loggingDataCode.NameCode#>, Value = <#=loggingDataCode.ValueCode#>},
192 | <#+
193 | }
194 | #>
--------------------------------------------------------------------------------
/T4Aspects/LoggingDataCodeGeneratorForArgumentsBasedOnTheLogAttribute.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="System.Core" #>
3 | <#@ import namespace="System.Collections.Generic" #>
4 | <#@ import namespace="System.Linq" #>
5 | <#@ import namespace="EnvDTE" #>
6 | <#@ include once="true" file="LoggingAspect.Core.tt"#><##>
7 | <#@ include once="true" file="Utilities\AttributeValueExtractor.tt"#><##>
8 | <#+
9 | public class LoggingDataCodeGeneratorForArgumentsBasedOnTheLogAttribute : IPreInvocationLoggingDataCodeGenerator
10 | {
11 | public LoggingDataCode[] Extract(CodeFunction method)
12 | {
13 | List loggingDataCodeList = new List();
14 |
15 | foreach (CodeParameter parameter in method.Parameters)
16 | {
17 | var attributes =
18 | parameter.Attributes
19 | .Cast()
20 | .Where(x => x.FullName == "LoggingAOP.LogAttribute")
21 | .ToList();
22 |
23 | foreach (var attribute in attributes)
24 | {
25 | var valueCode =
26 | parameter.Type.TypeKind == vsCMTypeRef.vsCMTypeRefString
27 | ? parameter.Name
28 | : parameter.Name + ".ToString()";
29 |
30 | var nameCode = "\"" + (AttributeValueExtractor.GetAttributeSingleStringParameterValueOrNull(attribute) ?? parameter.Name) +"\"";
31 |
32 | loggingDataCodeList
33 | .Add(
34 | new LoggingDataCode(
35 | nameCode,
36 | valueCode));
37 | }
38 | }
39 |
40 | return loggingDataCodeList.ToArray();
41 | }
42 | }
43 | #>
--------------------------------------------------------------------------------
/T4Aspects/LoggingDataCodeGeneratorForArgumentsBasedOnTheLogCountAttribute.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="System.Core" #>
3 | <#@ import namespace="EnvDTE" #>
4 | <#@ import namespace="System.Collections.Generic" #>
5 | <#@ import namespace="System.Linq" #>
6 | <#@ include once="true" file="LoggingAspect.Core.tt"#><##>
7 | <#@ include once="true" file="Utilities\AttributeValueExtractor.tt"#><##>
8 | <#+
9 | public class LoggingDataCodeGeneratorForArgumentsBasedOnTheLogCountAttribute : IPreInvocationLoggingDataCodeGenerator
10 | {
11 | public LoggingDataCode[] Extract(CodeFunction method)
12 | {
13 | List loggingDataCodeList = new List();
14 |
15 | foreach (CodeParameter parameter in method.Parameters)
16 | {
17 | var attributes =
18 | parameter.Attributes
19 | .Cast()
20 | .Where(x => x.FullName == "LoggingAOP.LogCountAttribute")
21 | .ToList();
22 |
23 | foreach (var attribute in attributes)
24 | {
25 | var valueCode =
26 | parameter.Type.TypeKind.HasFlag(vsCMTypeRef.vsCMTypeRefArray)
27 | ? parameter.Name + ".Length.ToString()"
28 | : parameter.Name + ".Count.ToString()";
29 |
30 | var nameCode = "\"" + (AttributeValueExtractor.GetAttributeSingleStringParameterValueOrNull(attribute) ?? parameter.Name) +"\"";
31 |
32 | loggingDataCodeList
33 | .Add(
34 | new LoggingDataCode(
35 | nameCode,
36 | valueCode));
37 | }
38 | }
39 |
40 | return loggingDataCodeList.ToArray();
41 | }
42 | }
43 | #>
--------------------------------------------------------------------------------
/T4Aspects/LoggingDataCodeGeneratorForReturnValueBasedOnTheLogAttribute.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="EnvDTE80" #>
3 | <#@ assembly name="System.Core" #>
4 | <#@ import namespace="EnvDTE" #>
5 | <#@ import namespace="EnvDTE80" #>
6 | <#@ import namespace="System.Collections.Generic" #>
7 | <#@ import namespace="System.Linq" #>
8 | <#@ include once="true" file="LoggingAspect.Core.tt"#><##>
9 | <#@ include once="true" file="Utilities\AttributeValueExtractor.tt"#><##>
10 | <#+
11 |
12 | public class LoggingDataCodeGeneratorForReturnValueBasedOnTheLogAttribute : IPostInvocationLoggingDataCodeGenerator
13 | {
14 | public LoggingDataCode[] Extract(CodeFunction method, string returnValueVariableName)
15 | {
16 | List loggingDataCodeList = new List();
17 |
18 | if(method.Type.TypeKind == vsCMTypeRef.vsCMTypeRefVoid )
19 | return new LoggingDataCode[]{};
20 |
21 | var attributes =
22 | method.Attributes
23 | .Cast()
24 | .Where(x => x.Target == "return" && x.FullName == "LoggingAOP.LogAttribute")
25 | .ToList();
26 |
27 | foreach (var attribute in attributes)
28 | {
29 | var valueCode =
30 | method.Type.TypeKind == vsCMTypeRef.vsCMTypeRefString
31 | ? "returnValue"
32 | : "returnValue.ToString()";
33 |
34 | var nameCode = "\"" + (AttributeValueExtractor.GetAttributeSingleStringParameterValueOrNull(attribute) ?? "Return Value") + "\"";
35 |
36 | loggingDataCodeList
37 | .Add(
38 | new LoggingDataCode(
39 | nameCode,
40 | valueCode));
41 | }
42 |
43 | return loggingDataCodeList.ToArray();
44 | }
45 | }
46 | #>
--------------------------------------------------------------------------------
/T4Aspects/LoggingDataCodeGeneratorForReturnValueBasedOnTheLogCountAttribute.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="EnvDTE80" #>
3 | <#@ assembly name="System.Core" #>
4 | <#@ import namespace="EnvDTE" #>
5 | <#@ import namespace="EnvDTE80" #>
6 | <#@ import namespace="System.Collections.Generic" #>
7 | <#@ import namespace="System.Linq" #>
8 | <#@ include once="true" file="LoggingAspect.Core.tt"#><##>
9 | <#@ include once="true" file="Utilities\AttributeValueExtractor.tt"#><##>
10 | <#+
11 | public class LoggingDataCodeGeneratorForReturnValueBasedOnTheLogCountAttribute : IPostInvocationLoggingDataCodeGenerator
12 | {
13 | public LoggingDataCode[] Extract(CodeFunction method, string returnValueVariableName)
14 | {
15 | List loggingDataCodeList = new List();
16 |
17 | if(method.Type.TypeKind == vsCMTypeRef.vsCMTypeRefVoid)
18 | return new LoggingDataCode[]{};
19 |
20 | var attributes =
21 | method.Attributes
22 | .Cast()
23 | .Where(x => x.Target == "return" && x.FullName == "LoggingAOP.LogCountAttribute")
24 | .ToList();
25 |
26 | foreach (var attribute in attributes)
27 | {
28 | var valueCode =
29 | method.Type.TypeKind.HasFlag(vsCMTypeRef.vsCMTypeRefArray)
30 | ? "returnValue.Length.ToString()"
31 | : "returnValue.Count.ToString()";
32 |
33 | var nameCode = "\"" + (AttributeValueExtractor.GetAttributeSingleStringParameterValueOrNull(attribute) ?? "Return Value") + "\"";
34 |
35 | loggingDataCodeList
36 | .Add(
37 | new LoggingDataCode(
38 | nameCode,
39 | valueCode));
40 | }
41 |
42 | return loggingDataCodeList.ToArray();
43 | }
44 | }
45 | #>
--------------------------------------------------------------------------------
/T4Aspects/MethodDescriptionLoggingDataCodeGenerator.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="EnvDTE80" #>
3 | <#@ assembly name="System.Core" #>
4 | <#@ import namespace="EnvDTE" #>
5 | <#@ import namespace="EnvDTE80" #>
6 | <#@ import namespace="System.Linq" #>
7 | <#@ include once="true" file="LoggingAspect.Core.tt"#><##>
8 | <#@ include once="true" file="Utilities\AttributeValueExtractor.tt"#><##>
9 | <#+
10 | public class MethodDescriptionLoggingDataCodeGenerator : IPreInvocationLoggingDataCodeGenerator
11 | {
12 | public LoggingDataCode[] Extract(CodeFunction method)
13 | {
14 | var attribute =
15 | method.Attributes
16 | .Cast()
17 | .FirstOrDefault(x => x.Target != "return" && x.FullName == "LoggingAOP.MethodDescriptionAttribute");
18 |
19 | var methodDescription =
20 | attribute == null
21 | ? method.Name
22 | : AttributeValueExtractor.GetAttributeSingleStringParameterValue(attribute);
23 |
24 | return new []
25 | {
26 | new LoggingDataCode(
27 | nameCode: "\"Method\"",
28 | valueCode: "\"" + methodDescription + "\"")
29 | };
30 | }
31 | }
32 | #>
--------------------------------------------------------------------------------
/T4Aspects/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("T4Aspects")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("T4Aspects")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("24148b11-2079-440a-a7d2-1dbdc0848855")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/T4Aspects/RetryAspect.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="EnvDTE80" #>
3 | <#@ assembly name="System.Core" #>
4 | <#@ import namespace="EnvDTE" #>
5 | <#@ import namespace="EnvDTE80" #>
6 | <#@ import namespace="System.Text" #>
7 | <#@ import namespace="System.Linq" #>
8 | <#@ include once="true" file="Utilities\MethodParametersGenerator.tt" #><##>
9 | <#@ include once="true" file="Utilities\MethodMatcher.tt"#><##>
10 | <#+
11 | public void GenerateRetryDecoratorForInterface(
12 | CodeInterface2 @interface)
13 | {
14 | string fullInterfaceName = @interface.FullName;
15 |
16 | var formattedInterfaceName = FormatInterfaceName(@interface.Name);
17 |
18 | string decoratorClassName = formattedInterfaceName + "RetryDecorator";
19 |
20 | var @namespace = @interface.Namespace.FullName;
21 |
22 | #>
23 |
24 | namespace <#= @namespace #>
25 | {
26 | using System;
27 | using System.Threading;
28 |
29 | public class <#=decoratorClassName#> : <#=fullInterfaceName#>
30 | {
31 | private readonly <#=fullInterfaceName#> decorated;
32 | private readonly int numberOfRetries;
33 | private readonly TimeSpan waitTimeBetweenRetries;
34 |
35 | public <#=decoratorClassName#>(
36 | <#=fullInterfaceName#> decorated,
37 | int numberOfRetries,
38 | TimeSpan waitTimeBetweenRetries)
39 | {
40 | this.decorated = decorated;
41 | this.numberOfRetries = numberOfRetries;
42 | this.waitTimeBetweenRetries = waitTimeBetweenRetries;
43 | }
44 |
45 | <#+
46 | PushIndent(new string(' ', 8));
47 | GenerateMethodsForInterface(@interface);
48 | PopIndent();
49 | #>
50 | }
51 |
52 | public static class ExtensionMethodsForRetryAspectFor<#= formattedInterfaceName#>
53 | {
54 | public static <#=fullInterfaceName#> ApplyRetryAspect(this <#=fullInterfaceName#> instance, int numberOfRetries, TimeSpan waitTimeBetweenRetries)
55 | {
56 | return new <#=decoratorClassName#>(instance, numberOfRetries, waitTimeBetweenRetries);
57 | }
58 | }
59 | }
60 | <#+
61 | }
62 |
63 | private string FormatInterfaceName(string name)
64 | {
65 | if (name.Length > 1 && name[0] == 'I' && char.IsUpper(name[1]))
66 | return name.Substring(1);
67 |
68 | return name;
69 | }
70 |
71 | private void GenerateMethodsForInterface(
72 | CodeInterface @interface)
73 | {
74 | foreach (CodeFunction interfaceMethod in @interface.Members.OfType())
75 | {
76 | bool isVoid = interfaceMethod.Type.TypeKind == vsCMTypeRef.vsCMTypeRefVoid;
77 |
78 | string methodReturnType =
79 | isVoid
80 | ? "void"
81 | : interfaceMethod.Type.AsFullName;
82 |
83 | string methodName = interfaceMethod.Name;
84 |
85 | #>
86 | public <#=methodReturnType#> <#=methodName#>(<#= MethodParameterGenerator.GenerateMethodParametersWithTypes(interfaceMethod)#>)
87 | {
88 | int retries = 0;
89 |
90 | while(true)
91 | {
92 | try
93 | {
94 | <#+
95 | if (isVoid)
96 | {
97 | #>
98 | decorated.<#=methodName #>(<#=MethodParameterGenerator.GenerateMethodParametersWithoutTypes(interfaceMethod) #>);
99 | return;
100 | <#+
101 | }
102 | else
103 | {
104 | #>
105 | return decorated.<#=methodName #>(<#=MethodParameterGenerator.GenerateMethodParametersWithoutTypes(interfaceMethod) #>);
106 | <#+
107 | }
108 | #>
109 | }
110 | catch
111 | {
112 | retries++;
113 |
114 | if(retries == numberOfRetries)
115 | throw;
116 |
117 | Thread.Sleep(waitTimeBetweenRetries);
118 | }
119 | }
120 | }
121 |
122 | <#+
123 | }
124 | }
125 | #>
--------------------------------------------------------------------------------
/T4Aspects/T4Aspects.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {24148B11-2079-440A-A7D2-1DBDC0848855}
8 | Library
9 | Properties
10 | T4Aspects
11 | T4Aspects
12 | v4.5.2
13 | 512
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug\
20 | DEBUG;TRACE
21 | prompt
22 | 4
23 |
24 |
25 | pdbonly
26 | true
27 | bin\Release\
28 | TRACE
29 | prompt
30 | 4
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
73 |
--------------------------------------------------------------------------------
/T4Aspects/Utilities/AttributeValueExtractor.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="System.Core" #>
3 | <#@ import namespace="EnvDTE" #>
4 | <#+
5 | public static class AttributeValueExtractor
6 | {
7 | public static string GetAttributeSingleStringParameterValueOrNull(CodeAttribute attribute)
8 | {
9 | if (string.IsNullOrWhiteSpace(attribute.Value))
10 | return null;
11 |
12 | return attribute.Value.Trim('"');
13 | }
14 |
15 | public static string GetAttributeSingleStringParameterValue(CodeAttribute attribute)
16 | {
17 | return attribute.Value.Trim('"');
18 | }
19 | }
20 | #>
--------------------------------------------------------------------------------
/T4Aspects/Utilities/ClassFinder.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="EnvDTE80" #>
3 | <#@ assembly name="System.Core" #>
4 | <#@ import namespace="EnvDTE" #>
5 | <#@ import namespace="EnvDTE80" #>
6 | <#@ import namespace="System.Collections.Generic" #>
7 | <#@ import namespace="System.Linq" #>
8 | <#+
9 | public static class ClassFinder
10 | {
11 | public static CodeClass2[] FindClassesInSolution(DTE dte, string[] names)
12 | {
13 | List list = new List();
14 |
15 | foreach (Project project in dte.Solution.Projects)
16 | {
17 | CodeClass2[] result = FindClassesInProject(project, names);
18 |
19 | list.AddRange(result);
20 | }
21 |
22 | return list.ToArray();
23 | }
24 |
25 | private static CodeClass2[] FindClassesInProject(Project project, string[] names)
26 | {
27 | List list = new List();
28 |
29 | if (project.Kind == ProjectKinds.vsProjectKindSolutionFolder)
30 | {
31 |
32 | foreach (ProjectItem projectItem in project.ProjectItems)
33 | {
34 | if(projectItem.SubProject != null)
35 | list.AddRange(FindClassesInProject(projectItem.SubProject, names));
36 | }
37 |
38 | return list.ToArray();
39 | }
40 |
41 | foreach (ProjectItem projectItem in project.ProjectItems)
42 | {
43 | CodeClass2[] result = FindClassInProjectItem(projectItem, names);
44 |
45 | list.AddRange(result);
46 | }
47 |
48 | return list.ToArray();
49 | }
50 |
51 | private static CodeClass2[] FindClassInProjectItem(ProjectItem projectItem, string[] names)
52 | {
53 | List list = new List();
54 |
55 | if (projectItem.ProjectItems != null)
56 | {
57 | foreach (ProjectItem subprojectItem in projectItem.ProjectItems)
58 | {
59 | CodeClass2[] subResult = FindClassInProjectItem(subprojectItem, names);
60 |
61 | list.AddRange(subResult);
62 | }
63 | }
64 |
65 | if (projectItem.FileCodeModel == null)
66 | return list.ToArray();
67 |
68 | CodeClass2[] result = FindClass(projectItem.FileCodeModel.CodeElements, names);
69 |
70 | list.AddRange(result);
71 |
72 | return list.ToArray();
73 | }
74 |
75 | private static CodeClass2[] FindClass(CodeElements elements, string[] names)
76 | {
77 | List list = new List();
78 |
79 | foreach (CodeElement element in elements)
80 | {
81 | if (element.Kind == vsCMElement.vsCMElementClass)
82 | {
83 | if (names.Contains(element.Name))
84 | list.Add((CodeClass2)element);
85 | }
86 | else if (element.Kind == vsCMElement.vsCMElementNamespace)
87 | {
88 | var codeNamespace = (CodeNamespace) element;
89 |
90 | CodeClass2[] result = FindClass(codeNamespace.Members, names);
91 |
92 | list.AddRange(result);
93 | }
94 | }
95 |
96 | return list.ToArray();
97 | }
98 | }
99 | #>
--------------------------------------------------------------------------------
/T4Aspects/Utilities/InterfaceFinder.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="EnvDTE80" #>
3 | <#@ assembly name="System.Core" #>
4 | <#@ import namespace="EnvDTE" #>
5 | <#@ import namespace="EnvDTE80" #>
6 | <#@ import namespace="System.Collections.Generic" #>
7 | <#@ import namespace="System.Linq" #>
8 | <#+
9 | public static class InterfaceFinder
10 | {
11 | public static CodeInterface2[] FindInterfacesInSolution(DTE dte, string[] names)
12 | {
13 | List list = new List();
14 |
15 | foreach (Project project in dte.Solution.Projects)
16 | {
17 | CodeInterface2[] result = FindInterfacesInProject(project, names);
18 |
19 | list.AddRange(result);
20 | }
21 |
22 | return list.ToArray();
23 | }
24 |
25 | private static CodeInterface2[] FindInterfacesInProject(Project project, string[] names)
26 | {
27 | List list = new List();
28 |
29 | if (project.Kind == ProjectKinds.vsProjectKindSolutionFolder)
30 | {
31 |
32 | foreach (ProjectItem projectItem in project.ProjectItems)
33 | {
34 | if(projectItem.SubProject != null)
35 | list.AddRange(FindInterfacesInProject(projectItem.SubProject, names));
36 | }
37 |
38 | return list.ToArray();
39 | }
40 |
41 | foreach (ProjectItem projectItem in project.ProjectItems)
42 | {
43 | CodeInterface2[] result = FindInterfaceInProjectItem(projectItem, names);
44 |
45 | list.AddRange(result);
46 | }
47 |
48 | return list.ToArray();
49 | }
50 |
51 | private static CodeInterface2[] FindInterfaceInProjectItem(ProjectItem projectItem, string[] names)
52 | {
53 | List list = new List();
54 |
55 | if (projectItem.ProjectItems != null)
56 | {
57 | foreach (ProjectItem subprojectItem in projectItem.ProjectItems)
58 | {
59 | CodeInterface2[] subResult = FindInterfaceInProjectItem(subprojectItem, names);
60 |
61 | list.AddRange(subResult);
62 | }
63 | }
64 |
65 | if (projectItem.FileCodeModel == null)
66 | return list.ToArray();
67 |
68 | CodeInterface2[] result = FindInterface(projectItem.FileCodeModel.CodeElements, names);
69 |
70 | list.AddRange(result);
71 |
72 | return list.ToArray();
73 | }
74 |
75 | private static CodeInterface2[] FindInterface(CodeElements elements, string[] names)
76 | {
77 | List list = new List();
78 |
79 | foreach (CodeElement element in elements)
80 | {
81 | if (element.Kind == vsCMElement.vsCMElementInterface)
82 | {
83 | if (names.Contains(element.Name))
84 | list.Add((CodeInterface2)element);
85 | }
86 | else if (element.Kind == vsCMElement.vsCMElementNamespace)
87 | {
88 | var codeNamespace = (CodeNamespace) element;
89 |
90 | CodeInterface2[] result = FindInterface(codeNamespace.Members, names);
91 |
92 | list.AddRange(result);
93 | }
94 | }
95 |
96 | return list.ToArray();
97 | }
98 | }
99 | #>
--------------------------------------------------------------------------------
/T4Aspects/Utilities/MethodMatcher.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="System.Core" #>
3 | <#@ import namespace="System.Linq" #>
4 | <#@ import namespace="EnvDTE" #>
5 | <#+
6 | public static class MethodMatcher
7 | {
8 | public static CodeFunction GetClassMethodFromInterfaceMethod(CodeFunction interfaceMethod, CodeClass @class)
9 | {
10 | var interfaceMethodSignature = GetMethodSignature(interfaceMethod);
11 |
12 | return @class.Members.OfType().Single(x => GetMethodSignature(x) == interfaceMethodSignature);
13 | }
14 |
15 | private static string GetMethodSignature(CodeFunction classMethod)
16 | {
17 | var value =
18 | vsCMPrototype.vsCMPrototypeParamDefaultValues |
19 | vsCMPrototype.vsCMPrototypeParamNames |
20 | vsCMPrototype.vsCMPrototypeParamTypes |
21 | vsCMPrototype.vsCMPrototypeType;
22 |
23 | return classMethod.Prototype[(int) value];
24 | }
25 | }
26 | #>
--------------------------------------------------------------------------------
/T4Aspects/Utilities/MethodParametersGenerator.tt:
--------------------------------------------------------------------------------
1 | <#@ assembly name="EnvDTE" #>
2 | <#@ assembly name="System.Core" #>
3 | <#@ import namespace="EnvDTE" #>
4 | <#@ import namespace="System.Text" #>
5 | <#@ import namespace="System.Linq" #>
6 | <#+
7 | public static class MethodParameterGenerator
8 | {
9 | public static string GenerateMethodParametersWithTypes(CodeFunction method)
10 | {
11 | return GenerateMethodParametersWithTypes(method, includeTypes: true);
12 | }
13 |
14 | public static string GenerateMethodParametersWithoutTypes(CodeFunction method)
15 | {
16 | return GenerateMethodParametersWithTypes(method, includeTypes: false);
17 | }
18 |
19 | private static string GenerateMethodParametersWithTypes(CodeFunction method, bool includeTypes)
20 | {
21 | var parameters = method.Parameters;
22 |
23 | StringBuilder sb = new StringBuilder();
24 |
25 | for(int i = 1 ; i <= parameters.Count ; i++)
26 | {
27 | var param = (CodeParameter) parameters.Item(i);
28 |
29 | if(i != 1)
30 | sb.Append(", ");
31 |
32 | if (includeTypes)
33 | {
34 | sb.Append(param.Type.AsFullName);
35 | sb.Append(" ");
36 | }
37 |
38 | sb.Append(param.Name);
39 | }
40 |
41 | return sb.ToString();
42 | }
43 | }
44 | #>
--------------------------------------------------------------------------------