홈>
Rubberduck의 최신 리팩토링 중 하나는 Extract Interface입니다. 이 리팩토링은 수업을 수강하고 모든 공개 회원을 표시하며 인터페이스에 포함 할 회원을 선택할 수 있습니다. 다음으로 인터페이스를 만들고
Implement <Interface Name>
를 추가합니다.
파일 맨 위로 이동하고 인터페이스 구현 을 호출하여 빈 인터페이스 멤버를 구현합니다. 안타깝게도 참조를 구문 분석하고 해결해야하는 시간으로 인해 기존 멤버의 이름을 바꾸지 않기로 결정했습니다.
리팩토링 모델입니다 :
public class ExtractInterfaceModel
{
private readonly RubberduckParserState _parseResult;
public RubberduckParserState ParseResult { get { return _parseResult; } }
private readonly IEnumerable<Declaration> _declarations;
public IEnumerable<Declaration> Declarations { get { return _declarations; } }
private readonly QualifiedSelection _selection;
public QualifiedSelection Selection { get { return _selection; } }
private readonly Declaration _targetDeclaration;
public Declaration TargetDeclaration { get { return _targetDeclaration; } }
public string InterfaceName { get; set; }
public List<InterfaceMember> Members { get; set; }
private static readonly DeclarationType[] DeclarationTypes =
{
DeclarationType.Class,
DeclarationType.Document,
DeclarationType.UserForm
};
public readonly string[] PrimitiveTypes =
{
Tokens.Boolean,
Tokens.Byte,
Tokens.Date,
Tokens.Decimal,
Tokens.Double,
Tokens.Long,
Tokens.LongLong,
Tokens.LongPtr,
Tokens.Integer,
Tokens.Single,
Tokens.String,
Tokens.StrPtr
};
public ExtractInterfaceModel(RubberduckParserState parseResult, QualifiedSelection selection)
{
_parseResult = parseResult;
_selection = selection;
_declarations = parseResult.AllDeclarations.ToList();
_targetDeclaration =
_declarations.SingleOrDefault(
item =>
!item.IsBuiltIn && DeclarationTypes.Contains(item.DeclarationType)
&& item.Project == selection.QualifiedName.Project
&& item.QualifiedSelection.QualifiedName == selection.QualifiedName);
InterfaceName = "I" + TargetDeclaration.IdentifierName;
Members = _declarations.Where(item => !item.IsBuiltIn &&
item.Project == _targetDeclaration.Project &&
item.ComponentName == _targetDeclaration.ComponentName &&
item.Accessibility == Accessibility.Public &&
item.DeclarationType != DeclarationType.Variable &&
item.DeclarationType != DeclarationType.Event)
.OrderBy(o => o.Selection.StartLine)
.ThenBy(t => t.Selection.StartColumn)
.Select(d => new InterfaceMember(d, _declarations))
.ToList();
}
}
발표자 :
public interface IExtractInterfacePresenter
{
ExtractInterfaceModel Show();
}
public class ExtractInterfacePresenter : IExtractInterfacePresenter
{
private readonly IExtractInterfaceView _view;
private readonly ExtractInterfaceModel _model;
public ExtractInterfacePresenter(IExtractInterfaceView view, ExtractInterfaceModel model)
{
_view = view;
_model = model;
}
public ExtractInterfaceModel Show()
{
if (_model.TargetDeclaration == null) { return null; }
_view.ComponentNames =
_model.TargetDeclaration.Project.VBComponents.Cast<VBComponent>().Select(c => c.Name).ToList();
_view.InterfaceName = _model.InterfaceName;
_view.Members = _model.Members;
if (_view.ShowDialog() != DialogResult.OK)
{
return null;
}
_model.InterfaceName = _view.InterfaceName;
_model.Members = _view.Members;
return _model;
}
}
다음으로 리팩토링이 온다 :
public class ExtractInterfaceRefactoring : IRefactoring
{
private readonly RubberduckParserState _state;
private readonly IRefactoringPresenterFactory<ExtractInterfacePresenter> _factory;
private readonly IActiveCodePaneEditor _editor;
private ExtractInterfaceModel _model;
public ExtractInterfaceRefactoring(RubberduckParserState state, IRefactoringPresenterFactory<ExtractInterfacePresenter> factory,
IActiveCodePaneEditor editor)
{
_state = state;
_factory = factory;
_editor = editor;
}
public void Refactor()
{
var presenter = _factory.Create();
if (presenter == null)
{
return;
}
_model = presenter.Show();
if (_model == null) { return; }
AddInterface();
}
public void Refactor(QualifiedSelection target)
{
_editor.SetSelection(target);
Refactor();
}
public void Refactor(Declaration target)
{
_editor.SetSelection(target.QualifiedSelection);
Refactor();
}
private void AddInterface()
{
var interfaceComponent = _model.TargetDeclaration.Project.VBComponents.Add(vbext_ComponentType.vbext_ct_ClassModule);
interfaceComponent.Name = _model.InterfaceName;
_editor.InsertLines(1, GetInterface());
var module = _model.TargetDeclaration.QualifiedSelection.QualifiedName.Component.CodeModule;
var implementsLine = module.CountOfDeclarationLines + 1;
module.InsertLines(implementsLine, "Implements " + _model.InterfaceName);
_state.RequestParse(ParserState.Ready);
var qualifiedSelection = new QualifiedSelection(_model.TargetDeclaration.QualifiedSelection.QualifiedName,
new Selection(implementsLine, 1, implementsLine, 1));
var implementInterfaceRefactoring = new ImplementInterfaceRefactoring(_state, _editor, new MessageBox());
implementInterfaceRefactoring.Refactor(qualifiedSelection);
}
private string GetInterface()
{
return "Option Explicit" + Environment.NewLine + string.Join(Environment.NewLine, _model.Members.Where(m => m.IsSelected));
}
}
지원 클래스
InterfaceMember
그리고
Parameter
:
public class Parameter
{
public string ParamAccessibility { get; set; }
public string ParamName { get; set; }
public string ParamType { get; set; }
public override string ToString()
{
return ParamAccessibility + " " + ParamName + " As " + ParamType;
}
}
public class InterfaceMember
{
public Declaration Member { get; set; }
public IEnumerable<Parameter> MemberParams { get; set; }
public string Type { get; set; }
public string MemberType { get; set; }
public string PropertyType { get; set; }
public bool IsSelected { get; set; }
public string MemberSignature
{
get
{
var signature = Member.IdentifierName + "(" +
string.Join(", ", MemberParams.Select(m => m.ParamType)) + ")";
return Type == null ? signature : signature + " As " + Type;
}
}
public string FullMemberSignature
{
get
{
var signature = Member.IdentifierName + "(" +
string.Join(", ", MemberParams) + ")";
return Type == null ? signature : signature + " As " + Type;
}
}
public InterfaceMember(Declaration member, IEnumerable<Declaration> declarations)
{
Member = member;
Type = member.AsTypeName;
GetMethodType();
MemberParams = declarations.Where(item => item.DeclarationType == DeclarationType.Parameter &&
item.ParentScope == Member.Scope)
.OrderBy(o => o.Selection.StartLine)
.ThenBy(t => t.Selection.StartColumn)
.Select(p => new Parameter
{
ParamAccessibility = ((VBAParser.ArgContext)p.Context).BYREF() == null ? Tokens.ByVal : Tokens.ByRef,
ParamName = p.IdentifierName,
ParamType = p.AsTypeName
})
.ToList();
if (PropertyType == "Get")
{
MemberParams = MemberParams.Take(MemberParams.Count() - 1);
}
IsSelected = false;
}
private void GetMethodType()
{
var context = Member.Context;
var subStmtContext = context as VBAParser.SubStmtContext;
if (subStmtContext != null)
{
MemberType = Tokens.Sub;
}
var functionStmtContext = context as VBAParser.FunctionStmtContext;
if (functionStmtContext != null)
{
MemberType = Tokens.Function;
}
var propertyGetStmtContext = context as VBAParser.PropertyGetStmtContext;
if (propertyGetStmtContext != null)
{
MemberType = Tokens.Property;
PropertyType = Tokens.Get;
}
var propertyLetStmtContext = context as VBAParser.PropertyLetStmtContext;
if (propertyLetStmtContext != null)
{
MemberType = Tokens.Property;
PropertyType = Tokens.Let;
}
var propertySetStmtContext = context as VBAParser.PropertySetStmtContext;
if (propertySetStmtContext != null)
{
MemberType = Tokens.Property;
PropertyType = Tokens.Set;
}
}
public override string ToString()
{
return "Public " + MemberType + " " + PropertyType + " " + FullMemberSignature + Environment.NewLine + "End " + MemberType +
Environment.NewLine;
}
}
이 대화 상자 코드는 다음과 같습니다 :
public partial class ExtractInterfaceDialog : Form, IExtractInterfaceView
{
public string InterfaceName
{
get { return InterfaceNameBox.Text; }
set { InterfaceNameBox.Text = value; }
}
private List<InterfaceMember> _members;
public List<InterfaceMember> Members
{
get { return _members; }
set
{
_members = value;
InitializeParameterGrid();
}
}
public List<string> ComponentNames { get; set; }
public ExtractInterfaceDialog()
{
InitializeComponent();
InterfaceNameBox.TextChanged += InterfaceNameBox_TextChanged;
InterfaceMembersGridView.CellValueChanged += InterfaceMembersGridView_CellValueChanged;
SelectAllButton.Click += SelectAllButton_Click;
DeselectAllButton.Click += DeselectAllButton_Click;
}
void InterfaceNameBox_TextChanged(object sender, EventArgs e)
{
ValidateNewName();
}
void InterfaceMembersGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
_members.ElementAt(e.RowIndex).IsSelected =
(bool) InterfaceMembersGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;
}
void SelectAllButton_Click(object sender, EventArgs e)
{
ToggleSelection(true);
}
void DeselectAllButton_Click(object sender, EventArgs e)
{
ToggleSelection(false);
}
private void InitializeParameterGrid()
{
InterfaceMembersGridView.AutoGenerateColumns = false;
InterfaceMembersGridView.Columns.Clear();
InterfaceMembersGridView.DataSource = Members;
InterfaceMembersGridView.AlternatingRowsDefaultCellStyle.BackColor = Color.Lavender;
InterfaceMembersGridView.MultiSelect = false;
var isSelected = new DataGridViewCheckBoxColumn
{
AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells,
Name = "IsSelected",
DataPropertyName = "IsSelected",
HeaderText = string.Empty,
ReadOnly = false
};
var signature = new DataGridViewTextBoxColumn
{
AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill,
Name = "Members",
DataPropertyName = "MemberSignature",
ReadOnly = true
};
InterfaceMembersGridView.Columns.AddRange(isSelected, signature);
}
void ToggleSelection(bool state)
{
foreach (var row in InterfaceMembersGridView.Rows.Cast<DataGridViewRow>())
{
row.Cells["IsSelected"].Value = state;
}
}
private void ValidateNewName()
{
var tokenValues = typeof(Tokens).GetFields().Select(item => item.GetValue(null)).Cast<string>().Select(item => item);
OkButton.Enabled = !ComponentNames.Contains(InterfaceName)
&& char.IsLetter(InterfaceName.FirstOrDefault())
&& !tokenValues.Contains(InterfaceName, StringComparer.InvariantCultureIgnoreCase)
&& !InterfaceName.Any(c => !char.IsLetterOrDigit(c) && c != '_');
InvalidNameValidationIcon.Visible = !OkButton.Enabled;
}
}
이 코드로 개선 할 수있는 모든 것을 알려주십시오. 사소한 개선이 많을수록 좋습니다. Nitpicks도 환영합니다.
- 답변 # 1
트렌드
- OpenCv의 폴더에서 여러 이미지 읽기 (python)
- 파이썬 셀레늄 모든 "href"속성 가져 오기
- html - 자바 스크립트 - 클릭 후 변경 버튼 텍스트 변경
- javascript - 현재 URL에서 특정 div 만 새로 고침/새로 고침
- JSP에 대한 클래스를 컴파일 할 수 없습니다
- JavaScript 변수를 HTML div에 '출력'하는 방법
- git commit - 자식 - 로컬 커밋 된 파일에 대한 변경을 취소하는 방법
- jquery - JavaScript로 현재 세션 값을 얻으시겠습니까?
- javascript - swiperjs에서 정지, 재생 버튼 추가
- python - 화면에서 찾은 요소를 찾을 수없는 경우 셀레늄
이 코드 섹션은 나에게 재미있다.
와이즈 비즈 와이즈 비즈이것은 다른 학급에 속한다고 생각합니다. 나는 그 클래스의 이름을 무엇으로할지 확실하지 않지만 이것들은 파서에 더 가깝습니다. 어쩌면 그들은
와이즈 비즈 수정자는 식별자에 다른 참조를 할당 할 수 없음을 의미합니다. 우리가 배열의 내부를 수정하는 것을 막는 것은 없습니다. 일종의 ReadOnlyCollection에 도달했습니다. 와이즈 비즈 는 기본 클래스로 설계되었으므로 유용한 스 니펫을 재사용 가능한 코드로 추출 할 수있는 또 하나의 이유가됩니다.
Tokens