Niezainicjowana lista bez określonego typu

0

Czy istnieje możliwość utworzenia jakiejś niezainicjowanej listy List<> bez określonego typu danych, a później przypisania do niej jakiejś istniejącej listy dowolnego typu? Wyobraźmy sobie taki przykładowy kod:

public List<int> inty = new List<int>();
public List<byte> bajty = new List<byte>();
public List<long> longi = new List<long>();

public void dopisz(byte liczba)
{	
	public List<T> pusta;
	
	if (liczba % 3 == 0) pusta = inty;
	else if (liczba % 3 == 1) pusta = bajty;
	else if (liczba % 3 == 2) pusta = longi;
	
	for (int i = 0; i < pusta.Length; i++)
	{
		pusta[i]+=liczba;
	}
}

W tym przykładzie funkcja "dopisz" dopisuje "liczba" do każdego elementu jednej z list, w zależności od jej reszty dzielenia przez trzy. Rzecz jasna w rzeczywistym kodzie zamiast pętli for jest znacznie dłuższy ciąg instrukcji, tak więc jeśli nie dałoby się użyć "pusta" to musiałby zostać on powtórzony trzykrotnie dla każdej z list. Niestety nie wiem jak należałoby taką listę "pusta" zainicjować, gdyż ani List<T> ani List<> nie jest prawidłowe. Jest jakiś inny sposób czy raczej trzeba będzie dla każdej listy pisać osobno?

0

lista która może przechowywać dowolny typ to ArrayList albo List<object>, ale to nie znaczy że jest to „dowolna lista” w sensie List<T>, a raczej „lista obiektów dowolnego typu”.
To co próbujesz zrobić, czyli uzależniać typ od jakiejś liczby to dziwoląg. Co chcesz przez to osiągnąć?

0

Może coś takiego.

  
List<int> intLista = new List<int>() {1, 2, 3};
List<string> strLista = new List<string>() {"1", "2", "3"};
var list = new object(); 

// jakiś kod

if(...) 
list = intLista;
else
list = strLista;

0

Proponuję Ci metodę generyczną w której, tak czy inaczej, w pewnym momencie musisz działać na konkretnym typie. Może twoją metodę (tę zastępującą pętlę for) też da się przerobić na metodę generyczną, a jeżeli nie to pozostaje Ci napisane trzech metod dla każdego z typów, które mogą być prywatne i wołane przez tę jedną publiczną "dopisz".

public List<int> inty = new List<int>();
            public List<byte> bajty = new List<byte>();
            public List<long> longi = new List<long>();

            public void dopisz<T>(object liczba) 
            {
                if (typeof(T) == typeof(int))
                {
                    //dopisanie żeby było się po czym iterować
                    inty.Add(Convert.ToInt32(liczba));
                    for (int i = 0; i < inty.Count; i++)
                    {
                        inty[i] += Convert.ToInt32(liczba);                        
                    }
                }
                else if (typeof(T) == typeof(long))
                {
                    longi.Add(Convert.ToInt64(liczba));
                    for (int i = 0; i < longi.Count; i++)
                    {
                        longi[i] += Convert.ToInt64(liczba);                        
                    }
                }
                else if (typeof(T) == typeof(byte))
                {
                    bajty.Add(Convert.ToByte(liczba));
                    for (int i = 0; i < bajty.Count; i++)
                    {
                        bajty[i] += Convert.ToByte(liczba);                        
                    }
                }
            }
0

var się nie da bo trzeba i tak od razu zainicjalizować, zaś jako object i tak będzie trzeba potem rzutować na konkretny typ, czyli tak czy inaczej powtarzać wszystko trzy razy oddzielnie :(

Azarien napisał(a):

To co próbujesz zrobić, czyli uzależniać typ od jakiejś liczby to dziwoląg. Co chcesz przez to osiągnąć?

W sumie to był tylko taki abstrakcyjny przykład nie mający związku z właściwym kodem, bo jest to fragment mojej pracy dyplomowej i wolałbym go na razie nigdzie publicznie nie zamieszczać. W każdym razie, przyjrzałem się kodowi jeszcze raz i znalazłem inny sposób na rozwiązanie problemu, co możnaby opisać nieco wierniejszym przykładem:

Załóżmy, że mamy trzy klasy: a, b i c. Każda z tych klas ma pole type typu byte, obiekty tych klas przechowywane są w trzech odpowiadających im listach, a do tego jest jeszcze funkcja bleh(). W formie kodu wygląda to tak:

public List<a> pierwsza = new List<a>();
public List<b> druga = new List<b>();
public List<c> trzecia = new List<c>();
 
public void bleh(char z, int i)
{
	public byte tmp;
	
	if (z == 'a') tmp = pierwsza[i].type;
	else if (z == 'b') tmp = druga[i].type;
	else if (z == 'c') tmp = trzecia[i].type;
	 
	// (tutaj wieeele linijek operacji na tmp)
}

Krótko mówiąc, bleh() pobiera znak i inta, znak wskazuje na jedną z trzech list, int na jej element, i na polu type tego elementu funkcja wykonuje operacje wspomniane w komentarzu (operuje na obiekcie, zmienia wartość type, znowu operuje, przywraca poprzednią wartość type, porównuje wyniki operacji etc.) Jest tego dosyć trochę więc żeby nie powtarzać wszystkiego trzy razy dla każdej listy, type jest od razu podstawiane jako tmp i później tylko na tmp dokonuje tych wszystkich operacji. Problem z kolei w tym, że nie wiem czy funkcja będzie zmieniać też wartość tego type czy samego tmp, a z tego co mi wiadomo to "ref" można używać tylko z argumentami funkcji. Da się jakoś zrobić, żeby tmp wskazywało na type, czy raczej trzeba będzie pisać to potrójnie?

1
using System;
using System.Collections.Generic;
 
namespace Program
{
    abstract class Base
    {
        public byte Type { get; set; }
    }
    
    class A : Base { public A() { Type = 10; } }
    class B : Base { }
    class C : Base { }
    
    class Program
    {
        Dictionary<char, int> dict = new Dictionary<char, int>();
        List<List<Base>> list = new List<List<Base>>();
 
        static void Main()
        {
            Program p = new Program();
            p.Init();
            p.Bleh('x', 2);
        }
        
        void Init()
        {
            dict.Add('x', 0);
            dict.Add('y', 1);
            dict.Add('z', 2);
            
            list.Add(new List<Base>());
            list[0].Add(new A());
            list[0].Add(new A());
            list[0].Add(new A());
            // ...
        }
        
        void Bleh(char z, int i)
        {
            Console.WriteLine(list[dict[z]][i].Type);
        }
    }
}

Moze cos podobnego do tego zrobisz?

0

Ale wtedy to bym musiał cały kod przepisywać na nowo :( A boję się teraz pod prawie sam koniec z tym wszystkim grzebać...

A nie dałoby się może zrobić w C# czegoś tak jak wskaźniki w innych językach, że zmienna tmp tylko by wskazywała na type a wszelkie zmiany na niej zmieniałyby też i type? Myślałem o czymś w rodzaju "ref byte tmp = type" ale z tego co wyczytałem to ref działa tylko na argumentach funkcji a dzisiaj nie mam dostępu do komputera z Visual Studio więc na razie nie mogę sprawdzić...

0

AFAIK mozesz normalnie uzywac pointerow w C#, tylko musisz to zrobic w bloku unsafe i wywolac metode gc.KeepAlive() i przekazac jej ten obiekt. Metoda ta zapobiega przenoszenia obiektu przez gc.

0

Jest tak jak n0name_l napisał. Dodam tylko że **unsafe ** idzie w parze ze słowem fixed (odsyłam do MSDN po więcej indformacji).

1 użytkowników online, w tym zalogowanych: 0, gości: 1