الإرشادات التفصيلية: توسيع قاعدة بيانات إعادة تسمية Refacإلىring إلى تشغيلها في ملفات نصية
في هذا الموضوع خطوة بخطوة التي سيتم إنشاء يثّبت، تسجيل واختبار مساهم جديد ل إعادة تسمية إعادة بناء التعليمات البرمجية. سيقوم هذا الهدف إعادة بناء التعليمات البرمجية بتوسيع القدرات Visual Studio Premiumأو Visual Studio Ultimate، لتمكين جهاز إعادة بناء التعليمات البرمجية قاعدة بيانات لإعادة تسمية مراجع إلى الكائنات قاعدة البيانات الموجودة في النص ملفات في قاعدة بيانات مشروع الخاص بك .
عندما كنت إضافة نوع إعادة بناء التعليمات البرمجية مساهم إعادة بناء التعليمات البرمجية جديد موجود، يجب استخدام فئة إدخال مساهم موجودة.
توضح هذه الإرشادات التفصيلية المهام التالية:
إنشاء تجميع جديد يحتوي على الفئات مخصص إعادة بناء التعليمات البرمجية الهدف.
يثّبت و regهوter تجميع، حيث إعادة بناء التعليمات البرمجية تستهدف هو المتوفرة في Visual Studio Premiumأو Visual Studio Ultimate.
إنشاء مشروع قاعدة بيانات بسيطة إلى اختبر الهدف refacإلىring كما هو متوقع.
المتطلبات الأساسية
تحتاج إلى المكونات التالية لاستكمال هذه الإرشادات التفصيلية:
يجب تثبيت Visual Studio 2010 Premiumأو Visual Studio 2010 Ultimate.
ويجب أن يمتلك عدة تطوير برامج Visual Studio 2010مثبتاً تشغيل جهاز الكمبيوتر الخاص بك. إلى ينزّل هذه المجموعة، راجع هذه الصفحة في موقع Microsoft Office 2010 Suite تشغيل ويب: SDK Visual Studio 2010.
إنشاء تجميع مع مخصص إعادة بناء التعليمات البرمجية الهدف
إلى إنشاء هدف refacإلىring cusإلىm أن تمكين تسمية refacإلىring إلى تعمل تشغيل ملفات نصية، يجب تطبيق فئة واحدة إلى توفر RefacإلىringContribuإلىr جديدة:
- RenameReferenceTextContributorContributor-هذا فئة بناء قائمة مقترحات تغيير الخاص بالرمز الذي تمت إعادة تسميته. عروض تغيير يتم لكل مرجع التي هو في نص الملف الذي هو في مشروع قاعدة بيانات.
قبل إنشاء هذه الفئة، يمكنك إنشاء مكتبة فئة، إضافة المطلوبة، و إضافة بعض تعليمات برمجية المساعد تسهل بعض تعليمات برمجية التي سيتم الكتابة فيما بعد في هذه معاينة.
إلى إنشاء رمز الفئة المكتبة والمساعد
إنشاء جديد C# فئة مكتبة مشروع و تسمية من RenameTextContributor.csproj.
إضافة مراجع إلى.NET التالية تجميعات:
Microsoft.بيانات.مخطط
Microsoft.بيانات.مخطط.ScriptDom
Microsoft.بيانات.مخطط.ScriptDom.sql
Microsoft.بيانات.مخطط.Sql
إضافة مراجع إلى التجميعات التالية التي سوف تجد في المجلد% 10.0\VSTSDB ملفات%\Microsoft برنامج Visual Studio:
Microsoft.بيانات.مخطط.أدوات.Sql.dll
Microsoft.VisualStudio.بيانات.مخطط.حزمة.dll
Microsoft.VisualStudio.بيانات.مخطط.حزمة.Sql.dll
إضافة مراجع إلى تجميعات التالية من Visual Studio 2010 تطوير مجموعة برامج (SDK):
Microsoft.VisualStudio.OLE.Interop.dll
Microsoft.VisualStudio.Shell.10.0.dll
Microsoft.VisualStudio.TextManager.Interop.dll
Microsoft.VisualStudio.Shell.Interop.dll
Microsoft.VisualStudio.Shell.Interop.8.0.dll
Microsoft.VisualStudio.Shell.Interop.9.0.dll
Microsoft.VisualStudio.Shell.Interop.10.0.dll
من مستكشف الحل، إعادة تسمية Class1.cs إلى SampleHelper.cs.
انقر نقراً مزدوجاً لفتحه في تعليمات برمجية SampleHelper.cs محرر.
ملاحظة
Th هو فئة المساعد هو مطابقاً للنص المساعد الذي تم استخدامه في معاينة لأنواع إعادة بناء التعليمات البرمجية مخصصة. يمكنك نسخ تعليمات برمجية المصدر من هذا المشروع إلى مشروع جديد لتوفير الوقت.
استبدال محتويات تعليمات برمجية محرر بالتعليمة البرمجية التالية:
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using Microsoft.Data.Schema.SchemaModel; using Microsoft.Data.Schema.ScriptDom.Sql; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Data.Schema.Package.Refactoring; using Microsoft.VisualStudio.Data.Schema.Package.UI; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.VisualStudio.TextManager.Interop; namespace MySamples.Refactoring { internal static class SampleHelper { public static String GetModelElementName(IModelElement modelElement) { SampleHelper.CheckNullArgument(modelElement, "modelElement"); return modelElement.ToString(); } /// <summary> /// Given a model element, returns its simple name. /// </summary> public static String GetModelElementSimpleName(IModelElement modelElement) { String separator = "."; String simpleName = String.Empty; String fullName = modelElement.ToString(); String[] nameParts = fullName.Split(separator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (nameParts.Length > 0) { simpleName = nameParts[nameParts.Length - 1]; // last part } if (simpleName.StartsWith("[") && simpleName.EndsWith("]")) { simpleName = simpleName.Substring(1, simpleName.Length - 2); } return simpleName; } /// <summary> /// Find all files in the project with the specified file extension /// </summary> public static List<string> GetAllFilesInProject(IVsHierarchy solutionNode, string fileExtension, bool visibleNodesOnly) { List<string> files = new List<string>(); if (null != solutionNode) { EnumProjectItems(solutionNode, fileExtension, files, VSConstants.VSITEMID_ROOT, // item id of solution root node 0, // recursion from solution node true, // hierarchy is Solution node visibleNodesOnly); // visibleNodesOnly } return files; } /// <summary> /// Enumerates recursively over the hierarchy items. /// </summary> /// <param name="hierarchy">hierarchy to enmerate over.</param> /// <param name="fileExtension">type of files we need to collect from the project</param> /// <param name="files">list of file paths</param> /// <param name="itemid">item id of the hierarchy</param> /// <param name="recursionLevel">Depth of recursion. For example, if recursion started with the Solution /// node, then : Level 0 -- Solution node, Level 1 -- children of Solution, etc.</param> /// <param name="hierIsSolution">true if hierarchy is Solution Node. </param> /// <param name="visibleNodesOnly">true if only nodes visible in the Solution Explorer should /// be traversed. false if all project items should be traversed.</param> private static void EnumProjectItems(IVsHierarchy hierarchy, string fileExtension, List<string> files, uint itemid, int recursionLevel, bool hierIsSolution, bool visibleNodesOnly) { int hr; IntPtr nestedHierarchyObj; uint nestedItemId; Guid hierGuid = typeof(IVsHierarchy).GUID; // Check first if this node has a nested hierarchy. hr = hierarchy.GetNestedHierarchy(itemid, ref hierGuid, out nestedHierarchyObj, out nestedItemId); if (VSConstants.S_OK == hr && IntPtr.Zero != nestedHierarchyObj) { IVsHierarchy nestedHierarchy = Marshal.GetObjectForIUnknown(nestedHierarchyObj) as IVsHierarchy; Marshal.Release(nestedHierarchyObj); if (nestedHierarchy != null) { EnumProjectItems(nestedHierarchy, fileExtension, files, nestedItemId, recursionLevel, false, visibleNodesOnly); } } else { // Check if the file extension of this node matches string fileFullPath; hierarchy.GetCanonicalName(itemid, out fileFullPath); if (CompareExtension(fileFullPath, fileExtension)) { // add matched file paths into the list files.Add(fileFullPath); } recursionLevel++; //Get the first child node of the current hierarchy being walked object pVar; hr = hierarchy.GetProperty(itemid, ((visibleNodesOnly || (hierIsSolution && recursionLevel == 1) ? (int)__VSHPROPID.VSHPROPID_FirstVisibleChild : (int)__VSHPROPID.VSHPROPID_FirstChild)), out pVar); ErrorHandler.ThrowOnFailure(hr); if (VSConstants.S_OK == hr) { // Use Depth first search so at each level we recurse to check if the node has any children // and then look for siblings. uint childId = GetItemId(pVar); while (childId != VSConstants.VSITEMID_NIL) { EnumProjectItems(hierarchy, fileExtension, files, childId, recursionLevel, false, visibleNodesOnly); hr = hierarchy.GetProperty(childId, ((visibleNodesOnly || (hierIsSolution && recursionLevel == 1)) ? (int)__VSHPROPID.VSHPROPID_NextVisibleSibling : (int)__VSHPROPID.VSHPROPID_NextSibling), out pVar); if (VSConstants.S_OK == hr) { childId = GetItemId(pVar); } else { ErrorHandler.ThrowOnFailure(hr); break; } } } } } /// <summary> /// Gets the item id. /// </summary> /// <param name="pvar">VARIANT holding an itemid.</param> /// <returns>Item Id of the concerned node</returns> private static uint GetItemId(object pvar) { if (pvar == null) return VSConstants.VSITEMID_NIL; if (pvar is int) return (uint)(int)pvar; if (pvar is uint) return (uint)pvar; if (pvar is short) return (uint)(short)pvar; if (pvar is ushort) return (uint)(ushort)pvar; if (pvar is long) return (uint)(long)pvar; return VSConstants.VSITEMID_NIL; } /// <summary> /// Check if the file has the expected extension. /// </summary> /// <param name="filePath"></param> /// <param name="extension"></param> /// <returns></returns> public static bool CompareExtension(string filePath, string extension) { bool equals = false; if (!string.IsNullOrEmpty(filePath)) { equals = (string.Compare(System.IO.Path.GetExtension(filePath), extension, StringComparison.OrdinalIgnoreCase) == 0); } return equals; } /// <summary> /// Read file content from a file /// </summary> /// <param name="filePath"> file path </param> /// <returns> file content in a string </returns> internal static string ReadFileContent(string filePath) { // Ensure that the file exists first. if (!File.Exists(filePath)) { Debug.WriteLine(string.Format("Cannot find the file: '{0}'", filePath)); return string.Empty; } string content; using (StreamReader reader = new StreamReader(filePath)) { content = reader.ReadToEnd(); reader.Close(); } return content; } /// <summary> /// Check null references and throw /// </summary> /// <param name="obj"></param> /// <param name="?"></param> public static void CheckNullArgument(object obj, string objectName) { if (obj == null) { throw new System.ArgumentNullException(objectName); } } /// <summary> /// Get offset of the fragment from an Identifier if the identifier.value matches the /// name we are looking for. /// </summary> /// <param name="identifier"></param> /// <param name="expectedName"></param> public static RawChangeInfo AddOffsestFromIdentifier( Identifier identifier, String expectedName, String newName, Boolean keepOldQuote) { RawChangeInfo change = null; if (identifier != null && String.Compare(expectedName, identifier.Value, true) == 0) { if (keepOldQuote) { QuoteType newQuote = QuoteType.NotQuoted; newName = Identifier.DecodeIdentifier(newName, out newQuote); newName = Identifier.EncodeIdentifier(newName, identifier.QuoteType); } change = new RawChangeInfo(identifier.StartOffset, identifier.FragmentLength, expectedName, newName); } return change; } public static IList<ChangeProposal> ConvertOffsets( string projectFullName, string fileFullPath, List<RawChangeInfo> changes, bool defaultIncluded) { // Get the file content into IVsTextLines IVsTextLines textLines = GetTextLines(fileFullPath); int changesCount = changes.Count; List<ChangeProposal> changeProposals = new List<ChangeProposal>(changesCount); for (int changeIndex = 0; changeIndex < changesCount; changeIndex++) { int startLine = 0; int startColumn = 0; int endLine = 0; int endColumn = 0; RawChangeInfo currentChange = changes[changeIndex]; int startPosition = currentChange.StartOffset; int endPosition = currentChange.StartOffset + currentChange.Length; int result = textLines.GetLineIndexOfPosition(startPosition, out startLine, out startColumn); if (result == VSConstants.S_OK) { result = textLines.GetLineIndexOfPosition(endPosition, out endLine, out endColumn); if (result == VSConstants.S_OK) { TextChangeProposal changeProposal = new TextChangeProposal(projectFullName, fileFullPath, currentChange.NewText); changeProposal.StartLine = startLine; changeProposal.StartColumn = startColumn; changeProposal.EndLine = endLine; changeProposal.EndColumn = endColumn; changeProposal.Included = defaultIncluded; changeProposals.Add(changeProposal); } } if (result != VSConstants.S_OK) { throw new InvalidOperationException("Failed to convert offset"); } } return changeProposals; } /// <summary> /// Get IVsTextLines from a file. If that file is in RDT, get text buffer from it. /// If the file is not in RDT, open that file in invisible editor and get text buffer /// from it. /// If failed to get text buffer, it will return null. /// </summary> /// <param name="fullPathFileName">File name with full path.</param> /// <returns>Text buffer for that file.</returns> private static IVsTextLines GetTextLines(string fullPathFileName) { System.IServiceProvider serviceProvider = DataPackage.Instance; IVsTextLines textLines = null; IVsRunningDocumentTable rdt = (IVsRunningDocumentTable)serviceProvider.GetService(typeof(SVsRunningDocumentTable)); if (rdt != null) { IVsHierarchy ppHier = null; uint pitemid, pdwCookie; IntPtr ppunkDocData = IntPtr.Zero; try { rdt.FindAndLockDocument((uint)(_VSRDTFLAGS.RDT_NoLock), fullPathFileName, out ppHier, out pitemid, out ppunkDocData, out pdwCookie); if (pdwCookie != 0) { if (ppunkDocData != IntPtr.Zero) { try { // Get text lines from the doc data IVsPersistDocData docData = (IVsPersistDocData)Marshal.GetObjectForIUnknown(ppunkDocData); if (docData is IVsTextLines) { textLines = (IVsTextLines)docData; } else { textLines = null; } } catch (ArgumentException) { // Do nothing here, it will return null stream at the end. } } } else { // The file is not in RDT, open it in invisible editor and get the text lines from it. IVsInvisibleEditor invisibleEditor = null; TryGetTextLinesAndInvisibleEditor(fullPathFileName, out invisibleEditor, out textLines); } } finally { if (ppunkDocData != IntPtr.Zero) Marshal.Release(ppunkDocData); } } return textLines; } /// <summary> /// Open the file in invisible editor in the running /// documents table (RDT), and get text buffer from that editor. /// </summary> /// <param name="fullPathFileName">File name with full path.</param> /// <param name="spEditor">The result invisible editor.</param> /// <param name="textLines">The result text buffer.</param> /// <returns>True, if the file is opened correctly in invisible editor.</returns> private static bool TryGetTextLinesAndInvisibleEditor(string fullPathFileName, out IVsInvisibleEditor spEditor, out IVsTextLines textLines) { System.IServiceProvider serviceProvider = DataPackage.Instance; spEditor = null; textLines = null; // Need to open this file. Use the invisible editor manager to do so. IVsInvisibleEditorManager spIEM; IntPtr ppDocData = IntPtr.Zero; bool result; Guid IID_IVsTextLines = typeof(IVsTextLines).GUID; try { spIEM = (IVsInvisibleEditorManager)serviceProvider.GetService(typeof(IVsInvisibleEditorManager)); spIEM.RegisterInvisibleEditor(fullPathFileName, null, (uint)_EDITORREGFLAGS.RIEF_ENABLECACHING, null, out spEditor); if (spEditor != null) { int hr = spEditor.GetDocData(0, ref IID_IVsTextLines, out ppDocData); if (hr == VSConstants.S_OK && ppDocData != IntPtr.Zero) { textLines = Marshal.GetTypedObjectForIUnknown(ppDocData, typeof(IVsTextLines)) as IVsTextLines; result = true; } else { result = false; } } else { result = false; } } finally { if (ppDocData != IntPtr.Zero) Marshal.Release(ppDocData); } return result; } } }
تشغيل انقر قائمة ملف حفظ SampleHelper.cs.
إضافة فئة يسمى من RawChangeInfo إلى المشروع.
في تعليمات برمجية محرر، قم بتحديث تعليمات برمجية بحيث تتطابق مع ما يلي:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MySamples.Refactoring { /// <summary> /// Helper class to encapsulate StartOffset, FragmentLength and change string from /// parser and SchemaAnalzyer. /// </summary> internal sealed class RawChangeInfo { private int _startOffset; private int _length; private string _oldText; private string _newText; public RawChangeInfo(int startOffset, int length, string oldText, string newText) { _startOffset = startOffset; _length = length; _oldText = oldText; _newText = newText; } public int StartOffset { get { return _startOffset; } set { _startOffset = value; } } public int Length { get { return _length; } } public string OldText { get { return _oldText; } } public string NewText { get { return _newText; } set { _newText = value; } } } }
في قائمة ملف ، انقر فوق حفظ RawChangeInfo.cs.
بعد ذلك، سوف تقوم بتعريف RenameReferenceTextContributor في فئة.
إلى تعريف الفئة RenameReferenceTextContribuإلىr
إضافة فئة باسم RenameReferenceTextContributor إلى مشروع.
في ediإلىr تعليمات برمجية، يتم تحديث استخدام عبارات إلى يطابق ما يلي:
using System; using System.Collections.Generic; using Microsoft.Data.Schema.Extensibility; using Microsoft.Data.Schema.Sql; using Microsoft.VisualStudio; using Microsoft.VisualStudio.Data.Schema.Package.Refactoring; using Microsoft.VisualStudio.Data.Schema.Package.Sql.Refactoring;
قم بتغيير مساحة الاسم إلى من MySamples.إعادة بناء التعليمات البرمجية:
namespace MySamples.Refactoring
قم بتحديث تعريف الفئة إلى يطابق ما يلي:
[DatabaseSchemaProviderCompatibility(typeof(SqlDatabaseSchemaProvider))] internal class RenameReferenceTextContributor : RefactoringContributor<RenameReferenceContributorInput> { }
تحدد السمة إلى التصريح أن هذا contribuإلىr متوافق مع أي موفري مخطط قاعدة بيانات المشتقة من SqlDatabaseSchemaProvider. الخاص بك فئة يجب أن يورث RefactoringContributor RenameReferenceContributorInput.
قم بتعريف الثوابت الإضافية و متغيرات عضو خاص:
#region const private const string TxtExtension = @".txt"; private const string PreviewFriendlyName = @"Text Files"; private const string PreviewDescription = @"Update text symbols in text files in the database project."; private const string PreviewWarningMessage = @"Updating text symbols in text files in the database project can cause inconsistency."; #endregion #region members private RefactoringPreviewGroup _textPreviewGroup; private List<String> _changingFiles; #endregion
الثوابت توفر المعلومات التي تظهر في "نافذة المعاينة". تستخدم الأعضاء إضافى للتمكن من مقطع صوتي في المجموعة معاينة و قائمة نص الملفات التي يتم تغييرها.
قم بإضافة الدالة الإنشائية الفئة:
#region ctor public RenameReferenceTextContributor() { _textPreviewGroup = new RefactoringPreviewGroup(PreviewFriendlyName); _textPreviewGroup.Description = PreviewDescription; _textPreviewGroup.WarningMessage = PreviewWarningMessage; _textPreviewGroup.EnableChangeGroupUncheck = true; _textPreviewGroup.EnableChangeUncheck = true; _textPreviewGroup.DefaultChecked = false; _textPreviewGroup.IncludeInCurrentProject = true; // This sample uses the default icon for the file, // but you could provide your own icon here. //RefactoringPreviewGroup.RegisterIcon(TxtExtension, "textfile.ico"); } #endregion
تهيئة المنشئ عنصر الطراز، قم بإنشاء مجموعة جديدة من معاينة وتهيئة الخصائص الخاصة به. يمكن أيضا تسجيل الرموز هنا، ليتم عرضها في "نافذة المعاينة" للخاصة ملف ملحقات اسم. لأن هناك هو بناء جملة لا يوجد تمييز للملفات النصية، تفعل regهوter غير الخدمة لغة الخاصة بملفات نصية.
يمنع PreviewGroupخاصية إلى بإرجاع مجموعة تم إنشاؤه عندما تم تاريخ الإنشاء هذا contribuإلىr:
/// <summary> /// Preview group for text files /// </summary> public override RefactoringPreviewGroup PreviewGroup { get { return _textPreviewGroup; } set { _textPreviewGroup = value; } }
يمنع ContributeChangesأسلوب إلى إرجاع قائمة مقترحات تغيير:
/// <summary> /// Contribute to the change proposals /// </summary> /// <param name="input">contributor input</param> /// <returns>List of change proposals with corresponding contributor inputs</returns> protected override Tuple<IList<ChangeProposal>, IList<ContributorInput>> ContributeChanges(RenameReferenceContributorInput input) { RenameReferenceContributorInput referenceInput = input as RenameReferenceContributorInput; if (referenceInput == null) { throw new ArgumentNullException("input"); } string projectFullName; referenceInput.RefactoringOperation.CurrentProjectHierarchy.GetCanonicalName(VSConstants.VSITEMID_ROOT, out projectFullName); return GetChangesForAllTextFiles(referenceInput, projectFullName, _textPreviewGroup.DefaultChecked, out _changingFiles); }
هذا الأسلوب باستدعاء الأسلوب GetAllChangesForAllTextFiles إلى بأداء معظم العمل.
أضف الأسلوب GetChangesForAllTextFiles إلى تكرار عبر قائمة الملفات النصية الموجودة في مشروع والحصول على تغييرات لكل ملف وتجميع تلك تغييرات في إلى قائمة مقترحات تغيير:
/// <summary> /// Get all changes from all text files. /// </summary> private static Tuple<IList<ChangeProposal>, IList<ContributorInput>> GetChangesForAllTextFiles( RenameReferenceContributorInput input, string projectFullName, bool defaultChecked, out List<String> changingFiles) { if (input == null) { throw new ArgumentNullException("input"); } changingFiles = new List<String>(); List<ChangeProposal> allChanges = new List<ChangeProposal>(); List<string> files = new List<string>(); files = SampleHelper.GetAllFilesInProject(input.RefactoringOperation.CurrentProjectHierarchy, TxtExtension, false); // process the text files one by one if (files != null && files.Count > 0) { int fileCount = files.Count; // Get all the changes for all txt files. for (int fileIndex = 0; fileIndex < fileCount; fileIndex++) { IList<ChangeProposal> changes = GetChangesForOneTextFile( input, projectFullName, files[fileIndex], defaultChecked); if (changes != null && changes.Count > 0) { allChanges.AddRange(changes); changingFiles.Add(files[fileIndex]); } } } return new Tuple<IList<ChangeProposal>, IList<ContributorInput>>(allChanges, null); }
تنفيذ الأسلوب GetChangesForOneTextFileMethod إلى إرجاع قائمة مقترحات تغيير التي تم تضمينها في ملف نصي مفرد:
/// <summary> /// Get all the change proposals from one text file. /// </summary> private static IList<ChangeProposal> GetChangesForOneTextFile( RenameReferenceContributorInput input, string projectFullName, string fileFullPath, bool defaultChecked) { const string separators = " \t \r \n \\()[]{}|.+-*/~!@#$%^&<>?:;"; string fileContent = SampleHelper.ReadFileContent(fileFullPath); IList<ChangeProposal> changeProposals= null; if (string.IsNullOrEmpty(fileContent)) { // return empty change list changeProposals = new List<ChangeProposal>(); } else { int startIndex = 0; int maxIndex = fileContent.Length - 1; string oldName = input.OldName; int oldNameLength = oldName.Length; List<RawChangeInfo> changes = new List<RawChangeInfo>(); while (startIndex < maxIndex) { // Text files do not understand schema object information // We do just case-insensitive string match (without schema info) // Only match whole word int offset = fileContent.IndexOf(oldName, startIndex, StringComparison.OrdinalIgnoreCase); // Cannot find match any more, stop the match if (offset < 0) { break; } startIndex = offset + oldNameLength; // match whole word: check before/after characters are separators if (offset > 0) { char charBeforeMatch = fileContent[offset - 1]; // match starts in the middle of a token, discard and move on if (!separators.Contains(charBeforeMatch.ToString())) { continue; } } if (offset + oldNameLength < maxIndex) { char charAfterMatch = fileContent[offset + oldNameLength]; // match ends in the middle of a token, discard and move on if (!separators.Contains(charAfterMatch.ToString())) { continue; } } RawChangeInfo change = new RawChangeInfo(offset, oldNameLength, input.OldName, input.NewName); changes.Add(change); } // convert index-based offsets to ChangeOffsets in ChangeProposals changeProposals = SampleHelper.ConvertOffsets( projectFullName, fileFullPath, changes, defaultChecked); } return changeProposals; }
لأن إعادة بناء التعليمات البرمجية توجيه هو غير على Transact-SQLبرنامج نصي أو كائن مخطط، وترتيب هو لا يستخدم أسلوب أنواع أو وظائف أما من Microsoft.Data.Schema.ScriptDomأو Microsoft.Data.Schema.Sql.SchemaModel. Th هو الهدف إعادة بناء التعليمات البرمجية يوفر تطبيق البحث والاستبدال للملفات النصية، لأنه لم تتوفر معلومات مخطط الرموز في الملفات النصية.
تشغيل انقر قائمة ملف حفظ RenameTextCتشغيلtributor.cs.
التالي، سيتم تكوين وبنية تجميع.
إلى التسجيل وبنية تجميع
تشغيل انقر قائمة مشروع خصائص RenameTextCتشغيلtributor.
انقر فوق علامة التبويب تسجيل الدخول.
انقر فوق توقيع تجميع.
في اختيار اسم المميز لمفاتيح ملف ، انقر فوق من <جديد>.
في إنشاء المفتاح اسم قوي صندوق حوار، في من اسم ملف المفتاح، اكتب من MyRefKey.
(اختياري) يمكنك تحديد كلمة مرور المفتاح الاسم المميز الخاص بك ملف.
انقر فوق موافق.
من القائمة ملف، انقر فوق حفظ الكل.
من القائمة Build (إنشاء)، انقر فوق Build Solution (إنشاء الحل).
بعد ذلك، يجب أن تقوم بتثبيت وتسجيل كـ sembly حيث يظهر كـ توفر اختبار شرط .
إلى يثّبت تجميع RenameTextContribuإلىr
قم بإنشاء مجلد باسم Myملحقات في المجلد% 10.0\VSTSDB\ملحقات ملفات%\Microsoft Visual Studio البرنامج.
قم بنسخ تجميع الموقعة (RenameTextContributor.dll) إلى 10.0\VSTSDB\ملحقات\Myملحقات ملفات%\Microsoft برنامج Visual Studio% مجلد.
ملاحظة
ننصح بعدم نسخ ملفات XML الخاصة بك مباشرة في 10.0\VSTSDB\ملحقات Files%\Microsoft برنامج Visual Studio% مجلد. إذا كنت تستخدم مجلد فرعي بدلاً من ذلك، إلى منع التغييرات غير المقصودة غير ذلك الملفات المتوفرة مع Visual Studio.
بعد ذلك، يجب تسجيل تجميع الخاص بك، نوع من ملحق ميزة ، أنه سيظهر في Visual Studio.
إلى تسجيل تجميع RenameTextContribuإلىr
قائمة عرض انقر فوق من Windows الأخرى، ومن ثم انقر فوق من نافذة الأوامر إلى فتح النافذة الأوامر.
في الإطار الأوامر، نوع التعليمة البرمجية التالية. ل FilePath، استبدل المسار و ملف اسم.dll المترجمة الخاصة بك ملف. تضمين علامات الاقتباس حول المسار و ملف اسم.
ملاحظة
بشكل افتراضي، مسار ملف.dll المترجمة الخاصة بك هو\bin\يصحح YourSolutionPath أو\bin\يطرح المنتج YourSolutionPath .
? System.Reflection.Assembly.LoadFrom("FilePath").FullName
? System.Reflection.Assembly.LoadFrom(@"FilePath").FullName
اضغط Enter.
قم بنسخ خط الناتجة إلى "حافظة". يجب على الخط لما يلي:
"RenameTextContributor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nnnnnnnnnnnnnnnn"
افتح محرر نص عادي، مثل المفكرة كـ.
قم بتوفير المعلومات التالية، قم بتحديد اسم التجميع الخاص بك، ورمز مفتاح عام، و نوع الملحق:
<?xml version="1.0" encoding="utf-8" ?> <extensions assembly="" version="1" xmlns="urn:Microsoft.Data.Schema.Extensions" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:Microsoft.Data.Schema.Extensions Microsoft.Data.Schema.Extensions.xsd"> <extension type="MySamples.Refactoring.RenameReferenceTextContributor" assembly="RenameTextContributor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=<enter key here>" enabled="true" /> </extensions>
قم بتسجيل الفئة التي ترث من RefactoringContributor.
قم بحفظ الملف ك RenameTextContributor.ملحقات.xml في المجلد% 10.0\VSTSDB\ملحقات\MyExtensions ملفات%\Microsoft برنامج Visual Studio.
قم بإغلاق Visual Studio.
بعد ذلك، ستقوم بإنشاء مشروع قاعدة بيانات بسيطة جداً إلى اختبار نوع refacإلىring الجديد.
اختبار "المساهمين" جديدة إعادة بناء التعليمات البرمجية
إلى إنشاء مشروع قاعدة بيانات
في قائمة ملف ، أشر إلى جديد ، و انقر مشروع.
تحت القوالب المثبتة، المتوقعة و العقدة قاعدة البياناتو انقر فوق العقدة SQL الخادم.
في قائمة القوالب، انقر فوق مشروع قاعدة بيانات في SQL الخادم 2008.
انقر فوق موافق إلى قبول اسم مشروع الافتراضي وقم بإنشاء مشروع.
يتم تاريخ الإنشاء مشروع قاعدة بيانات فارغ.
إلى إضافة جدول مع المفتاح أساسي
في قائمة عرض ، انقر فوق عرض مخطط قاعدة بيانات.
في طريقة عرض المخطط، توسيع العقدة رسوم تخطيطية توسيع العقدة dbo ، انقر نقراً مزدوجاً فوق عقدة جداول ، أشر إلى إضافةوانقر فوق جدول.
في صندوق الحوار الخاص ب إضافة عنصر جديد? ، في الاسم، اكتب الموظفين .
ملاحظة
عن قصد استخدام أحرف صغيرة للبدء في اسم الجدول.
انقر فوق موافق.
قم بتوسيع العقدة جداول ، يمين-انقر فوق العقدة الموظف ، أشر إلى إضافةوانقر فوق من المفتاح أساسي.
في إضافة عنصر جديد? صندوق حوار، في الاسم، اكتب من PK_Employee_column_1.
انقر فوق موافق.
التالي، تتم إضافة ملف نصي إلى قاعدة بيانات مشروع الذي يحتوي على مرجع إلى جدول الموظفين.
إلى إضافة ملف نصي يحتوي على اسم الجدول
في مستكشف الحل، يمين-انقر فوق عقدة مشروع قاعدة بيانات، أشر إلى إضافةوانقر فوق عنصر جديد?.
في إضافة عنصر جديد? صندوق حوار، في القائمة فئات ، انقر فوق قوالب Studio Visual Basic.
في القائمة قوالب ، انقر فوق ملف نص .
في الاسم، نوع من SampleText1.txt.
في محرر تعليمات برمجية، قم بإضافة نص التالي:
This is documentation for the employee table. Any changes made to the employee table name should also be reflected in this text file.
في قائمة ملف ، انقر فوق حفظ SampleText1.txt.
بعد ذلك، سيتم استخدام نوع refacإلىring الجديد إلى تغيير الجدول اسم وكافة المراجع إلى عليه.
إلى استخدم مساهم إعادة بناء التعليمات البرمجية الجديدة لتحديث اسم الجدول
في عرض مخطط، انقر نقراً مزدوجاً فوق عقدة جدول الموظفين ، وأشر إلى إعادة بناء التعليمات البرمجية ، و انقر فوق إعادة التسمية.
في إعادة تسمية صندوق حوار، في من اسم جديد، اكتب من [شخص].
في تغييرات صندوق الحوار المعاينة قبل، التمرير من خلال مجموعات تغيير حتى تظهر المجموعة ملفات نصية.
مثيلات كلا من الموظفين في النص ملف سيتم سرد. يمكنك تعريف فئات التي تمكن هذا النوع الجديد من إعادة بناء التعليمات البرمجية في هذه معاينة. تحديد خانة اختيار بجانب إلى كل تغيير.
انقر فوق تطبيق.
اسم الجدول هو محدث أن الشخص، في "عرض" مخطط "ومحتويات الملف SampleText1.txt.
الخطوات التالية
يمكنك إنشاء أهداف refacإلىring إضافى، أو يمكنك إنشاء أنواع جديدة من refacإلىring، إلى تقليل الجهد المقترنة بإجراء تغييرات المتكررة إلى مشروع قاعدة بيانات الخاصة بك.
راجع أيضًا:
المهام
الإرشادات التفصيلية: إنشاء نوع جديد من قاعدة بيانات بحالة الأحرف لتغيير إلى Refacإلىring