Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Kr3/Kr3.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.4.33403.182
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kr3", "Kr3\Kr3.csproj", "{5B9C8390-F227-4F23-81BA-AB1885C1DF32}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestsReflector", "TestsReflector\TestsReflector.csproj", "{15B74937-BD20-4D2E-BBC1-49BA7ABDCF10}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5B9C8390-F227-4F23-81BA-AB1885C1DF32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B9C8390-F227-4F23-81BA-AB1885C1DF32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B9C8390-F227-4F23-81BA-AB1885C1DF32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B9C8390-F227-4F23-81BA-AB1885C1DF32}.Release|Any CPU.Build.0 = Release|Any CPU
{15B74937-BD20-4D2E-BBC1-49BA7ABDCF10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{15B74937-BD20-4D2E-BBC1-49BA7ABDCF10}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15B74937-BD20-4D2E-BBC1-49BA7ABDCF10}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15B74937-BD20-4D2E-BBC1-49BA7ABDCF10}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B0556365-C55B-4AF6-8ACA-ACBA1E439626}
EndGlobalSection
EndGlobal
11 changes: 11 additions & 0 deletions Kr3/Kr3/Kr3.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Library</OutputType>
</PropertyGroup>

</Project>
249 changes: 249 additions & 0 deletions Kr3/Kr3/Reflector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
using System.Linq.Expressions;
using System.Reflection;

namespace Kr3;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

namespace лучше писать первой строкой в файле, хотя дело вкуса


public class Reflector

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Надо комментарии

{
private readonly string filePath;

public Reflector(string filePath) => this.filePath = filePath;

private static string GetVisibilityFromClass(Type someClass)
{
if (someClass.IsNestedPrivate)
{
return "private ";
}
else if (someClass.IsNestedPublic)
{
return "public ";
}
else if (someClass.IsNestedFamily)
{
return "protected ";
}
else if (someClass.IsNestedAssembly)
{
return "internal ";
}
return "";
}

private static string GetStaticOrNotFromClass(Type someClass)
{
return someClass.IsAbstract && someClass.IsSealed ? "static " : "";
}
Comment on lines +33 to +36

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут и ниже лучше через => писать


private static string GetVisibilityFromField(FieldInfo someField)
{
if (someField.IsPrivate)
{
return "private ";
}
else if (someField.IsPublic)
{
return "public ";
}
else if (someField.IsFamily)
{
return "protected ";
}
else if (someField.IsAssembly)
{
return "internal ";
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кстати, есть ещё protected internal :)

return "";
}

private static string GetStaticOrNotFromField(FieldInfo someField)
{
return someField.IsStatic ? "static " : "";
}

private static string GetStaticOrNotFromMethod(MethodInfo someMethod)
{
return someMethod.IsStatic ? "static " : "";
}

private static string GetVisibilityFromMethod(MethodInfo someMethod)
{
if (someMethod.IsPrivate)
{
return "private ";
}
else if (someMethod.IsPublic)
{
return "public ";
}
else if (someMethod.IsFamily)
{
return "protected ";
}
else if (someMethod.IsAssembly)
{
return "internal ";
}
return "";
}

private static string GetVisibilityFromConstructor(ConstructorInfo constructorInfo)
{
if (constructorInfo.IsPrivate)
{
return "private ";
}
else if (constructorInfo.IsPublic)
{
return "public ";
}
else if (constructorInfo.IsFamily)
{
return "protected ";
}
else if (constructorInfo.IsAssembly)
{
return "internal ";
}
return "";
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так-то MethodInfo и ConstructorInfo — потомки MethodBase (потому что они суть методы), и IsPrivate/IsPublic/и т.д. — это свойства MethodBase. Так что один из этих двух методов не нужен.


private void WriteParameters(StreamWriter writer, ParameterInfo[] parameters)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Можно было бы сделать решение несколько более ООПшным, если бы разделить читалку структуры класса и писалку результатов в разные классы.

{
var first = true;
foreach (var parameter in parameters)
{
if (first)
{
writer.Write($"{parameter.ParameterType} {parameter.Name}");
first = false;
}
else
{
writer.Write($" ,{parameter.Name}");
}
}
}

public void PrintStructure(Type someClass)
{
string className = someClass.Name;
string file = $"{filePath}\\{className}.cs";

using var writer = new StreamWriter(file);

var visibility = GetVisibilityFromClass(someClass);
var staticOrNotStatic = GetStaticOrNotFromClass(someClass);
var interfaces = someClass.GetInterfaces();
if (interfaces.Length == 0)
{
writer.WriteLine($"{visibility}{staticOrNotStatic}class {className}");
}
else
{
writer.Write($"{visibility}{staticOrNotStatic}class {className} : ");
var first = true;
foreach (var element in interfaces)
{
if (first)
{
writer.Write($"{element.Name}");
first = false;
}
else
{
writer.Write($" : {element.Name}");
}
}
writer.WriteLine();
}
writer.WriteLine("{");

var constructors = someClass.GetConstructors();
foreach (var constructor in constructors)
{
writer.Write($"\t{GetVisibilityFromConstructor(constructor)}{className}(");
WriteParameters(writer, constructor.GetParameters());
writer.WriteLine(") {}");
}
var fields = someClass.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
foreach (var field in fields)
{
writer.WriteLine($"\t{GetVisibilityFromField(field)}{GetStaticOrNotFromField(field)}{field};");
}

var methods = someClass.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly);
foreach (var method in methods)
{
writer.Write($"\t{GetVisibilityFromMethod(method)}{GetStaticOrNotFromMethod(method)}{method.Name} (");
WriteParameters(writer, method.GetParameters());
writer.WriteLine(") {throw new OperationCanceledException()}");
}

var nestedClasses = someClass.GetNestedTypes();
foreach (var nestedClass in nestedClasses)
{
PrintStructure(nestedClass);
}

writer.WriteLine("}");
}

private static bool CheckIfThereIsMethodFromOneClassInAnother(MethodInfo[] methodsB, MethodInfo methodA)
{
var methodB = methodsB.FirstOrDefault(m => m.Name == methodA.Name && m.GetParameters().
Select(p => p.ParameterType).SequenceEqual(methodA.GetParameters().Select(p => p.ParameterType)));
return methodB != null;
}

private static void WriteDifferentMethods(StreamWriter writer,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну и механизм диффов, видимо, можно было бы в отдельный класс вынести. Тут у Вас принцип единственности ответственности настолько нарушен, насколько это возможно.

MethodInfo[] methodsFirst, MethodInfo[] methodsSecond)
{
foreach (var methodA in methodsFirst)
{
if (!CheckIfThereIsMethodFromOneClassInAnother(methodsSecond, methodA))
{
writer.Write($"{methodA.Name}\n");
}
}
}
private static void WriteDifferentFields(StreamWriter writer,
Comment on lines +209 to +210

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
private static void WriteDifferentFields(StreamWriter writer,
}
private static void WriteDifferentFields(StreamWriter writer,

FieldInfo[] fieldsFirst, FieldInfo[] fieldsSecond)
{
foreach (var fieldA in fieldsFirst)
{
if (!CheckIfThereIsFieldFromOneClassInAnother(fieldsSecond, fieldA))
{
writer.Write($"{fieldA.Name}\n");
}
}
}

private static bool CheckIfThereIsFieldFromOneClassInAnother(FieldInfo[] fieldsB, FieldInfo fieldA)
{
var fieldB = fieldsB.FirstOrDefault(f => f.Name == fieldA.Name && f.FieldType == fieldA.FieldType);
return fieldB != null;
}

public void DiffClasses(Type a, Type b)
{
string file = $"{filePath}/difference.txt";

using var writer = new StreamWriter(file);

WriteDifferentFields(writer, a.GetFields(), b.GetFields());
WriteDifferentFields(writer, b.GetFields(), a.GetFields());
WriteDifferentMethods(writer, a.GetMethods(), b.GetMethods());
WriteDifferentMethods(writer, b.GetMethods(), a.GetMethods());

var nestedClassesA = a.GetNestedTypes();
var nestedClassesB = b.GetNestedTypes();
foreach (var nestedClassA in nestedClassesA)
{
foreach (var nestedClassB in nestedClassesB)
{
DiffClasses(nestedClassA, nestedClassB);
}
}
}
}
16 changes: 16 additions & 0 deletions Kr3/TestsReflector/AnotherSum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace TestsReflector;

public class AnotherSum
{
private int val;

public AnotherSum(int value)
{
val = value;
}

public void AddToSum(int num)
{
val += num;
}
}
16 changes: 16 additions & 0 deletions Kr3/TestsReflector/TestClassSum.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace TestsReflector;

public class TestClassSum
{
private int val;

public TestClassSum(int value)
{
val = value;
}

public void Add(int num)
{
val += num;
}
}
54 changes: 54 additions & 0 deletions Kr3/TestsReflector/TestsReflector.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace TestsReflector;

using Kr3;
using System.Net.WebSockets;

public class Tests
{
[Test]
public void TestWithTestPrintStructure()
{
var sum = new TestClassSum(0);
var typeSum = sum.GetType();
var reflector = new Reflector(Path.Combine(TestContext.CurrentContext.TestDirectory, "forTests"));
reflector.PrintStructure(typeSum);
using var reader = new StreamReader((Path.Combine(TestContext.CurrentContext.TestDirectory, "forTests", "CheckTestClassSum.cs")));
var linesForCheck = reader.ReadToEnd().Split('\n');
using var anotherReader = new StreamReader((Path.Combine(TestContext.CurrentContext.TestDirectory, "forTests", "TestClassSum.cs")));
var linesFromReflector = anotherReader.ReadToEnd().Split('\r');

var arrayStringsWithoutSpecialSymbols = new string[linesFromReflector.Length];

var i = 0;
foreach (var line in linesFromReflector)
{
var newLine = line.Replace("\n", "");
arrayStringsWithoutSpecialSymbols[i] = newLine;
i++;
}

i = 0;
var j = 0;
while (i < linesForCheck.Length || j < arrayStringsWithoutSpecialSymbols.Length)
{
Assert.That(linesForCheck[i], Is.EqualTo(arrayStringsWithoutSpecialSymbols[j]));
++i;
++j;
}
}

[Test]
public void TestWithTestClassDiffClasses()
{
var sum = new TestClassSum(0);
var typeSum = sum.GetType();
var anotherSum = new AnotherSum(0);
var typeAnotherSum= anotherSum.GetType();
var reflector = new Reflector(Path.Combine(TestContext.CurrentContext.TestDirectory,"forTests"));
reflector.DiffClasses(typeSum, typeAnotherSum);
using var reader = new StreamReader((Path.Combine(TestContext.CurrentContext.TestDirectory, "forTests", "difference.txt")));
var lines = reader.ReadToEnd().Split('\n');
Assert.That(lines[0], Is.EqualTo("Add"));
Assert.That(lines[1], Is.EqualTo("AddToSum"));
}
}
Loading