diff --git a/UniqueList/List.Src/ElementExistsException.cs b/UniqueList/List.Src/ElementExistsException.cs
new file mode 100644
index 0000000..ce0d7b6
--- /dev/null
+++ b/UniqueList/List.Src/ElementExistsException.cs
@@ -0,0 +1,9 @@
+namespace Lists;
+
+public class ElementExistsException: Exception
+{
+ public ElementExistsException() { }
+ public ElementExistsException(string message) : base(message) { }
+
+ public ElementExistsException(string message, Exception innerException) : base(message, innerException) { }
+}
diff --git a/UniqueList/List.Src/IList.cs b/UniqueList/List.Src/IList.cs
new file mode 100644
index 0000000..2fb064e
--- /dev/null
+++ b/UniqueList/List.Src/IList.cs
@@ -0,0 +1,11 @@
+namespace Lists;
+
+public interface IList
+{
+ void Add(int value);
+ void Insert(int index, int value);
+ int[] ToArray();
+ int RemoveAt(int index);
+ int FindValue(int index);
+ int Count { get; }
+}
diff --git a/UniqueList/List.Src/List.cs b/UniqueList/List.Src/List.cs
new file mode 100644
index 0000000..7c06cee
--- /dev/null
+++ b/UniqueList/List.Src/List.cs
@@ -0,0 +1,264 @@
+using System.Data.Common;
+using System.Dynamic;
+using System.Reflection.Metadata.Ecma335;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks.Dataflow;
+using System.Xml;
+
+namespace Lists;
+
+///
+/// An implementation of linked list
+///
+public class List : IList
+{
+ protected class ListElement
+ {
+ public ListElement? Next;
+ public ListElement? Previous;
+ public int Value;
+ public ListElement(int value)
+ {
+ Value = value;
+
+ Next = null;
+ Previous = null;
+ }
+ }
+
+ public List()
+ {
+ Count = 0;
+ }
+
+ ///
+ /// Method to insert value at given index
+ ///
+ /// Where to insert value
+ /// Value to insert
+ /// Exception is thrown if index is less than 0 or
+ /// bigger than list.Count and it is impossible to insert value
+ public virtual void Insert(int index, int value)
+ {
+ if (index > Count || index < 0)
+ {
+ throw new IndexOutOfRangeException();
+ }
+
+ var newElement = new ListElement(value);
+
+ if (index == Count)
+ {
+ if (Count == 0)
+ {
+ head = newElement;
+ }
+ if (bottom is not null)
+ {
+ newElement.Previous = bottom;
+ bottom.Next = newElement;
+ }
+ bottom = newElement;
+ ++Count;
+ return;
+ }
+
+ if (index == 0)
+ {
+ newElement = new ListElement(value);
+
+ if (head is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+
+ head.Previous = newElement;
+ newElement.Next = head;
+ head = newElement;
+ ++Count;
+ return;
+ }
+
+ var currenElement = FindNode(index);
+ newElement.Next = currenElement;
+ newElement.Previous = currenElement.Previous;
+ if (currenElement.Previous is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+ currenElement.Previous.Next = newElement;
+ currenElement.Previous = newElement;
+ ++Count;
+ }
+
+ ///
+ /// Adds value to the end of list
+ ///
+ /// Value to add
+ public virtual void Add(int value)
+ {
+ var newElement = new ListElement(value);
+ if (Count == 0)
+ {
+ head = newElement;
+ bottom = newElement;
+ }
+ else if (Count == 1)
+ {
+
+ if (head is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+
+ head.Next = newElement;
+ newElement.Previous = head;
+ }
+ else
+ {
+ if (bottom is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+ bottom.Next = newElement;
+ newElement.Previous = bottom;
+ }
+ bottom = newElement;
+ ++Count;
+ }
+
+ ///
+ /// Method to get an int array containing all the values from list in the same order
+ ///
+ /// Array with values
+ public int[] ToArray()
+ {
+ var output = new int[Count];
+ var currenElement = head;
+ for (int i = 0; i < Count; ++i)
+ {
+ if (currenElement is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+ output[i] = currenElement.Value;
+ currenElement = currenElement.Next;
+ }
+
+ return output;
+ }
+
+ ///
+ /// Method allowing to remove value at given index
+ ///
+ /// Index of element to remove
+ /// Value of this element
+ /// Thrown if there is no element with such index in the list
+ public int RemoveAt(int index)
+ {
+ if (index > Count - 1 || index < 0 || Count == 0)
+ {
+ throw new IndexOutOfRangeException();
+ }
+
+ if (index == Count - 1)
+ {
+ if (Count == 0)
+ {
+ head = null;
+ bottom = null;
+ }
+ else
+ {
+ if (bottom is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+ bottom = bottom.Previous;
+ }
+ }
+
+ int value;
+
+ if (index == 0)
+ {
+ if (head is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+ value = head.Value;
+ head = head.Next;
+ --Count;
+ return value;
+ }
+
+ var element = FindNode(index);
+ value = element.Value;
+ if (element.Next is null || element.Previous is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+ element.Next.Previous = element.Previous;
+ element.Previous.Next = element.Next;
+ --Count;
+ return value;
+ }
+
+ ///
+ /// Method to get a value of an element at a givent index
+ ///
+ /// Index of an element to find
+ /// Value of an element
+ /// Thrown if there is no element with such index in the list
+ public int FindValue(int index)
+ {
+ if (index > Count - 1 || index < 0)
+ {
+ throw new IndexOutOfRangeException("Index is out of range");
+ }
+
+ var element = FindNode(index);
+
+ return element.Value;
+ }
+
+ protected ListElement FindNode(int index)
+ {
+ ListElement? currenElement;
+ if (index < Count / 2)
+ {
+ currenElement = head;
+ for (int i = 0; i < index; ++i)
+ {
+ if (currenElement is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+ currenElement = currenElement.Next;
+ }
+ }
+ else
+ {
+ currenElement = bottom;
+ for (int i = Count - 1; i > index; --i)
+ {
+ if (currenElement is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+ currenElement = currenElement.Previous;
+ }
+ }
+
+ if (currenElement is null)
+ {
+ throw new InvalidOperationException("List does not work correctly");
+ }
+
+ return currenElement;
+ }
+
+ public int Count { get; private set; }
+ protected ListElement? head = null;
+ protected ListElement? bottom = null;
+}
diff --git a/UniqueList/List.Src/List.csproj b/UniqueList/List.Src/List.csproj
new file mode 100644
index 0000000..206b89a
--- /dev/null
+++ b/UniqueList/List.Src/List.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/UniqueList/List.Src/Program.cs b/UniqueList/List.Src/Program.cs
new file mode 100644
index 0000000..7cd323b
--- /dev/null
+++ b/UniqueList/List.Src/Program.cs
@@ -0,0 +1,138 @@
+using Lists;
+
+
+
+class Program
+{
+ public static void Main()
+ {
+ string options = """
+ What kind of list do you want to create? Write number to console to choose
+ 0 - List
+ 1 - UniqueList
+ """;
+
+ Console.WriteLine(options);
+ int listType;
+ while (!int.TryParse(Console.ReadLine(), out listType) || listType > 1 || listType < 0)
+ {
+ Console.WriteLine("Incorrect input");
+ Console.Write(options);
+ }
+ Console.WriteLine();
+
+ IList list;
+ if (listType == 0)
+ {
+ list = new List();
+ }
+ else
+ {
+ list = new UniqueList();
+ }
+
+ bool running = true;
+ while (running)
+ {
+ options = """
+ 0 - Exit
+ 1 - Add element to list
+ 2 - Insert element to list
+ 3 - Remove element from list
+ 4 - Print list
+ Write number to console to choose option
+ """;
+
+ Console.WriteLine(options);
+
+ int option;
+ while (!int.TryParse(Console.ReadLine(), out option) || option > 4 || option < 0)
+ {
+ Console.WriteLine("Incorrect input");
+ Console.WriteLine(options);
+ }
+
+ switch (option)
+ {
+ case 0:
+ {
+ running = false;
+ break;
+ }
+ case 1:
+ {
+ var value = UserInputTryParse("Write value you want to add");
+ try
+ {
+ list.Add(value);
+ }
+ catch (ElementExistsException)
+ {
+ Console.WriteLine("You have already added this element earlier");
+ }
+ break;
+ }
+ case 2:
+ {
+ var index = UserInputTryParse("Write an index where you want to insert an element");
+ var value = UserInputTryParse("Write value you want to insert");
+
+ try
+ {
+ list.Insert(index, value);
+ }
+ catch (OutOfRangeException)
+ {
+ Console.WriteLine("Index is out of range");
+ }
+ catch (ElementExistsException)
+ {
+ Console.WriteLine("You have already added this element earlier");
+ }
+ break;
+ }
+ case 3:
+ {
+ var index = UserInputTryParse("Write an index where you want to delete an element");
+ try
+ {
+ list.RemoveAt(index);
+ }
+ catch (OutOfRangeException)
+ {
+ Console.WriteLine("Index is out of range");
+ }
+ break;
+ }
+ case 4:
+ {
+ Console.Write("[");
+ for (int i = 0; i < list.Count; ++i)
+ {
+ Console.Write(list.FindValue(i));
+ if (i != list.Count - 1)
+ {
+ Console.Write(", ");
+ }
+ }
+ Console.Write("]\n");
+ break;
+ }
+ }
+ Console.WriteLine();
+ }
+ }
+
+ private static int UserInputTryParse(string message)
+ {
+ Console.WriteLine(message);
+ int userInput;
+ while (!int.TryParse(Console.ReadLine(), out userInput))
+ {
+ Console.WriteLine("Incorrect input");
+ Console.WriteLine(message);
+ }
+
+ return userInput;
+ }
+}
diff --git a/UniqueList/List.Src/UniqueList.cs b/UniqueList/List.Src/UniqueList.cs
new file mode 100644
index 0000000..b21ebef
--- /dev/null
+++ b/UniqueList/List.Src/UniqueList.cs
@@ -0,0 +1,62 @@
+using System.ComponentModel;
+
+namespace Lists;
+
+///
+/// Modification of List that doesn't allow you to keep more than one value with the same value
+///
+public class UniqueList : List
+{
+ private bool Contains(int value)
+ {
+ if (Count == 0)
+ {
+ return false;
+ }
+
+ var currenElement = head;
+ for (int i = 0; i < Count; ++i)
+ {
+ if (currenElement.Value == value)
+ {
+ return true;
+ }
+ currenElement = currenElement.Next;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Adds value to the end of list. Throws an exception if element is already in list
+ ///
+ /// Value to add
+ /// Thrown if this element already exists in list
+ public override void Add(int value)
+ {
+ if (Contains(value))
+ {
+ throw new ElementExistsException("Such element has already been added");
+ }
+
+ base.Add(value);
+ }
+
+ ///
+ /// Method to insert value at given index. Throws an exception if element is already in list
+ ///
+ /// Where to insert value
+ /// Value to insert
+ /// Exception is thrown if index is less than 0 or
+ /// bigger than list.Count and it is impossible to insert value
+ /// Thrown if this element already exists in list
+ public override void Insert(int index, int value)
+ {
+ if (Contains(value))
+ {
+ throw new ElementExistsException("Such element has already been added");
+ }
+
+ base.Insert(index, value);
+ }
+}
diff --git a/UniqueList/List.Tests/List.Tests.cs b/UniqueList/List.Tests/List.Tests.cs
new file mode 100644
index 0000000..04581ba
--- /dev/null
+++ b/UniqueList/List.Tests/List.Tests.cs
@@ -0,0 +1,70 @@
+namespace List.Tests;
+using Lists;
+
+public class ListTests
+{
+ [Test]
+ public void AddTest()
+ {
+ var list = new List();
+ list.Add(1);
+ list.Add(2);
+ list.Add(3);
+ list.Add(4);
+ var result = list.ToArray();
+ Assert.That(result, Is.EqualTo(new int[4] { 1, 2, 3, 4 }));
+ }
+
+ [Test]
+ public void InsertTest()
+ {
+ var list = new List();
+ list.Insert(0, 1);
+ list.Insert(1, 2);
+ list.Insert(2, 3);
+ list.Insert(3, 4);
+ var result = list.ToArray();
+ Assert.That(result, Is.EqualTo(new int[4] { 1, 2, 3, 4 }));
+ list.Insert(2, 5);
+ list.Insert(4, 6);
+ result = list.ToArray();
+ Assert.That(result, Is.EqualTo(new int[6] { 1, 2, 5, 3, 6, 4 }));
+ }
+
+ [Test]
+ public void TestOutOfRangeCase()
+ {
+ var list = new List();
+ Assert.Throws(() => list.Insert(10, 6));
+ Assert.Throws(() => list.Insert(-10, 6));
+
+ Assert.Throws(() => list.RemoveAt(10));
+ Assert.Throws(() => list.RemoveAt(-10));
+
+ Assert.Throws(() => list.FindValue(10));
+ Assert.Throws(() => list.FindValue(-10));
+ }
+
+ [Test]
+ public void TestRemove()
+ {
+ var list = new List();
+ list.Add(1);
+ list.Add(2);
+ list.Add(3);
+ list.Add(4);
+ list.RemoveAt(2);
+ var result = list.ToArray();
+ Assert.That(result, Is.EqualTo(new int[3] {1, 2, 4}));
+ list.RemoveAt(0);
+ result = list.ToArray();
+ Assert.That(result, Is.EqualTo(new int[2] {2, 4}));
+ list.RemoveAt(1);
+ result = list.ToArray();
+ foreach (var item in result)
+ {
+ Console.WriteLine(item);
+ }
+ Assert.That(result, Is.EqualTo(new int[1] {2}));
+ }
+}
diff --git a/UniqueList/List.Tests/List.Tests.csproj b/UniqueList/List.Tests/List.Tests.csproj
new file mode 100644
index 0000000..81fde4d
--- /dev/null
+++ b/UniqueList/List.Tests/List.Tests.csproj
@@ -0,0 +1,28 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/UniqueList/List.Tests/UniqueList.Tests.cs b/UniqueList/List.Tests/UniqueList.Tests.cs
new file mode 100644
index 0000000..4328df3
--- /dev/null
+++ b/UniqueList/List.Tests/UniqueList.Tests.cs
@@ -0,0 +1,13 @@
+namespace List.Tests;
+using Lists;
+
+public class UniqueListTests
+{
+ [Test]
+ public void TestElementAlreadyExistsException()
+ {
+ var uniqueList = new UniqueList();
+ uniqueList.Add(1);
+ Assert.Throws(() => uniqueList.Add(1));
+ }
+}
diff --git a/UniqueList/UniqueList.sln b/UniqueList/UniqueList.sln
new file mode 100644
index 0000000..59d2e88
--- /dev/null
+++ b/UniqueList/UniqueList.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "List", "List.Src\List.csproj", "{ED63D80C-A9CA-420F-834E-D699C06C8A2F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "List.Tests", "List.Tests\List.Tests.csproj", "{6EC4DA67-6869-4EE6-A493-3AFBE7601FCB}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {ED63D80C-A9CA-420F-834E-D699C06C8A2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {ED63D80C-A9CA-420F-834E-D699C06C8A2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {ED63D80C-A9CA-420F-834E-D699C06C8A2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {ED63D80C-A9CA-420F-834E-D699C06C8A2F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6EC4DA67-6869-4EE6-A493-3AFBE7601FCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6EC4DA67-6869-4EE6-A493-3AFBE7601FCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6EC4DA67-6869-4EE6-A493-3AFBE7601FCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6EC4DA67-6869-4EE6-A493-3AFBE7601FCB}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal