Avatar
jt.e
Člen
Avatar
jt.e:

Zdravím, zajímá mě ještě jedna věc:
Jak vytvořit třídu podobného typu jako je String?
Tedy třídu, která není modifikovatelná, lze ji změnit pouze tak, že se vytvoří nová, lze ji inicializovat jako string: string s = "abc";

Editováno 10.10.2015 20:33
 
Odpovědět 10.10.2015 20:32
Avatar
Odpovídá na jt.e
Petr Čech (czubehead):

Nejspíš bys udělal struct s privátním konstruktorem a implicitní konverzí z právě třeba toho stringu.

Nahoru Odpovědět 10.10.2015 21:12
Why so serious? -Joker
Avatar
jt.e
Člen
Avatar
jt.e:

strukturu si dokážu představit, ale string je "public sealed class String : IComparable, ICloneable, IConvertible, IComparable<Strin­g>, IEnumerable<char>, IEnumerable, IEquatable<Strin­g>"

 
Nahoru Odpovědět 10.10.2015 22:23
Avatar
Odpovídá na jt.e
Ondřej Štorc:

Když použiješ (System.)String tak je stejné jako string. Je to vlastně alias (mám to od tuď). To definice třídy String je vcelku jasná. Říká že z třídy String nejde dědit a implementuje rozhraní IComparable, ICloneable, IConvertible, IComparable<Strin­g>, IEnumerable<char>, IEnumerable, IEquatable<String>. Všechno to je popsaný ve zdejším OOP tutoriálu.

Nahoru Odpovědět 10.10.2015 22:32
Život je příliš krátký na to, abychom bezpečně odebírali USB z počítače..
Avatar
jt.e
Člen
Avatar
jt.e:

že String == string chápu na to stačí i F12..

jinak už to začínám chápat:
pro inicializaci stačí přepsat implicit operator, jak píše czubehead, něco jako:

public static implicit operator MyClass(String s)

takže ještě přijít jak na to to:

public static implicit operator MyClass(MyClass s)

zkrátka aby šlo pak udělat toto:

MyClass a;
MyClass b = a;

bez toho abych předával pouze odkaz, ale bylo to klonování třídy

 
Nahoru Odpovědět 10.10.2015 23:31
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na jt.e
patrik.valkovic:
public static MyClass operator = (MyClass x);
Editováno 10.10.2015 23:35
Nahoru Odpovědět 10.10.2015 23:35
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
patrik.valkovic
Šéfredaktor
Avatar
patrik.valkovic:

už mi nejde dit, tak kecám. Tento operátor nejde přetížit. Nevím sice proč, ale je to tak.
https://msdn.microsoft.com/…bkb459w.aspx
Nicméně tam píšo něco o implicitním přetypování, třeba to pomůže.

Nahoru Odpovědět 10.10.2015 23:39
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
jt.e
Člen
Avatar
Odpovídá na patrik.valkovic
jt.e:

jde ale pouze takto:
public static implicit operator MyClass(String x);
public static implicit operator MyClass(int x);
public static implicit operator MyClass(bool x);
...
ale takto to nejde:
public static implicit operator MyClass(MyClass x);
hlásí to chybu:
User-defined operator cannot take an object of the enclosing type and convert to an object of the enclosing type

zatím jsem nenašel řešení

 
Nahoru Odpovědět 10.10.2015 23:48
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na jt.e
Jan Vargovský:

To co chceš se dělá v c# tak, že naimplementuješ IClonable a pak voláš Copy

var a = new A();
var copyOfA = (A)a.Copy();

Implementace metody Copy můžeš dělat několika způsoby:

  1. Kopírování 1:1 všech věcí, které chceš zkopírovat
  2. Zavolání MemberwiseCopy() z třídy Object
  3. Projetí reflexí a překopírování jednotlivých věcí
  4. Použít nějaký mapper (třeba AutoMappper, ale nezkoušel jsem)

Pozn. u klonování se tady používají dva termíny a to DeepCopy a ShallowCopy. Oba mají nějaké rozdíly, tak si když tak dohledej jaký je mezi nimi rozdíl, já jdu na oběd :D Určitě je to v dokumentaci někde uvedené u příkladu užití MemberwiseCopy.

 
Nahoru Odpovědět 11.10.2015 12:54
Avatar
jt.e
Člen
Avatar
Odpovídá na Jan Vargovský
jt.e:

to já vím, IClonable chápu a používám.
Já to na co se ptám, zatím nepotřebuju. Ale už mě kolikrát napadlo, že při vytvoření kopie stringu se .Copy() nedává. A nenapadá mě proč.

 
Nahoru Odpovědět 11.10.2015 14:02
Avatar
Milan Křepelka
Redaktor
Avatar
Milan Křepelka:

U deep copy se dělají i kopie všech objektů. U shallow copy je jenom zkopírují odkazy.

 
Nahoru Odpovědět 11.10.2015 14:07
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na jt.e
Jan Vargovský:

Jo, už to vidím. Tohle je napsané už v kompilátoru (nemám to podložené), ale je to jen prostě zjednodušení zápisu, abys nemusel psát:

string s = new string(new char[] { 'a', 'b', 'c' });

tak můžeš napsat

string s = "abc";

Zdroj beru intuici, protože podobný způsob je použit např. u delegátů.

Editováno 11.10.2015 15:11
 
Nahoru Odpovědět 11.10.2015 15:08
Avatar
jt.e
Člen
Avatar
Odpovídá na Jan Vargovský
jt.e:

Jestli jsem Tě správně pochopil, tak si myslíš, že takhle funguje kompilátor (string je speciální součást kompilátoru), a podobně fungující třída se klasickým způsobem nedá vytvořit (takže tím nemá cenu ztrácet čas).

 
Nahoru Odpovědět 11.10.2015 18:14
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na jt.e
patrik.valkovic:

http://tipsandtricks.runicsoft.com/…utables.html
http://stackoverflow.com/…utable-class

Tohle by ti mělo pomoct. V principu si udržuješ vnitřní stav, tak jak je, aby se nemohl měnit. Tak funguje i string.

Nahoru Odpovědět 11.10.2015 18:19
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na jt.e
Jan Vargovský:

Dá se vytvořit, jen prostě vytváření instance bude o pár znaků delší.

 
Nahoru Odpovědět 11.10.2015 18:36
Avatar
Jakub Šárník:

Ve skutečnosti je to všechno trochu jinak. Pokud do instance stringu přiřadíš jinej string, tak se string nebude klonovat, ale zkopíruješ jen referenci, jako u každé jiné třídy.

 
Nahoru Odpovědět  -1 11.10.2015 19:58
Avatar
jt.e
Člen
Avatar
Odpovídá na Jakub Šárník
jt.e:

nemyslím si.
Vyzkoušej si to:

class Program
{
    static void Main(string[] args)
    {
        string s1 = "1111";
        string s2 = s1;

        s2 = "2222";

        Console.WriteLine(s1);
        Console.WriteLine(s2);
        //změnou s2 se s1 nezmění
        Console.ReadKey();
    }
}

Tady jde pouze o předání reference:

class Program
{
    static void Main(string[] args)
    {
        StringBuilder s1 = new StringBuilder("1111");
        StringBuilder s2 = s1;

        s2[0] = '+';

        Console.WriteLine(s1);
        Console.WriteLine(s2);
        //zde se změnou s2 změní i s1
        Console.ReadKey();
    }
}
 
Nahoru Odpovědět 11.10.2015 21:35
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na Jakub Šárník
Jan Vargovský:

Teoreticky jo, prakticky je to úplně jedno, protože je string immutable.

 
Nahoru Odpovědět 11.10.2015 21:37
Avatar
Odpovídá na jt.e
Jakub Šárník:

Ne, tam pak změníš referenci, takže se logicky první nezmění a druhej bude odkazovat na novou referenci

 
Nahoru Odpovědět 11.10.2015 21:38
Avatar
jt.e
Člen
Avatar
Odpovídá na Jan Vargovský
jt.e:

Ale můžeš novou instanci třídy (pokud není statická), vytvořit pouze pomocí new ne jen pomocí operátoru =, jako u stringu

string a = "----";
string b = a;
 
Nahoru Odpovědět 11.10.2015 21:42
Avatar
Odpovídá na jt.e
Jakub Šárník:

Ne, tady tam ukládáš jen referenci :-)

Editováno 11.10.2015 21:44
 
Nahoru Odpovědět 11.10.2015 21:43
Avatar
jt.e
Člen
Avatar
Odpovídá na Jakub Šárník
jt.e:

teď sis vyvrátil, co jsi před tím napsal :)

 
Nahoru Odpovědět 11.10.2015 21:44
Avatar
Jakub Šárník:

Jde to ověřit takhle:

string a = "abc";
string b = a;
Console.WriteLine(Object.ReferenceEquals(a, b)); //true
 
Nahoru Odpovědět 11.10.2015 21:45
Avatar
Odpovídá na jt.e
Jakub Šárník:

Nevyvrátil, nebo nechápu, kam tím míříš

 
Nahoru Odpovědět 11.10.2015 21:46
Avatar
jt.e
Člen
Avatar
Odpovídá na Jakub Šárník
jt.e:

Nevyvrátil, nebo nechápu, kam tím míříš

Ve skutečnosti je to všechno trochu jinak. Pokud do instance stringu přiřadíš jinej string, tak se string nebude klonovat, ale zkopíruješ jen referenci, jako u každé jiné třídy.

Ne, tam pak změníš referenci, takže se logicky první nezmění a druhej bude odkazovat na novou referenci

 
Nahoru Odpovědět 11.10.2015 21:48
Avatar
jt.e
Člen
Avatar
jt.e:

string a = "abc";
string b = "abc";
Console.Write­Line(Object.Re­ferenceEquals(a, b)); //true

 
Nahoru Odpovědět 11.10.2015 21:48
Avatar
Odpovídá na jt.e
Jakub Šárník:

No to je sice pravda, ale proč bych si měl něco vyvracet? Nechápu co jsem si měl čím vyvrátit :-D

 
Nahoru Odpovědět 11.10.2015 21:51
Avatar
jt.e
Člen
Avatar
Odpovídá na Jakub Šárník
jt.e:

"se string nebude klonovat, ale zkopíruješ jen referenci"
"tam pak změníš referenci, takže se logicky první nezmění a druhej bude odkazovat na novou referenci"

připadá Ti to stejné tvrzení?

 
Nahoru Odpovědět 11.10.2015 21:54
Avatar
Odpovídá na jt.e
Jakub Šárník:

Ale ono se to taky vztahuje k něčemu jinýmu.

Tady zkopíruješ odkaz (referenci) a obě proměnné tak odkazují na stejnej kus paměti:

string a = "abc";
string b = a;

Tady ale změníš v druhém stringu referenci a tak bude odkazovat na něco jinýho:

string a = "abc";
string b = a; //Zatím stejná reference jako a
b = "cba" //A teď už je jiná, ale a zůstává stejný, protože je to jinej objekt alokovanej jinde
 
Nahoru Odpovědět 11.10.2015 21:58
Avatar
jt.e
Člen
Avatar
Odpovídá na Jakub Šárník
jt.e:

Tady máš ještě jeden důkaz:

class Program
    {
        static void Main(string[] args)
        {
            string s = "ssss";
            string n = "Ssss";
            SetText(ref s, n);

            Console.WriteLine(s);
            Console.WriteLine(n);

            Console.ReadKey();
        }

        static void SetText(ref string s, string new_s)
        {
            s = new_s;
            new_s = "0000000";
        }
    }

Klasickou můžeš změnit přes parametr, aniž bys tam dal ref

class Program
{
    static void Main(string[] args)
    {
        TestClass s = new TestClass("ssss");
        TestClass n = new TestClass("Ssss");
        SetText(ref s, n);

        Console.WriteLine(s.txt);
        Console.WriteLine(n.txt);


        Console.ReadKey();
    }

    static void SetText(ref TestClass s, TestClass new_s)
    {
        s.txt = new_s.txt;
        new_s.txt = "0000000";
    }
}

class TestClass
{
    public string txt;

    public TestClass(string t)
    {
        txt = t;
    }
}
 
Nahoru Odpovědět 11.10.2015 21:59
Avatar
Odpovídá na jt.e
Jakub Šárník:

Důkaz čeho? Tady nejde o nic jinýho než že string je immutable a

string a = "a";

je jen syntaktickej cukr pro

String a = new String("a");
 
Nahoru Odpovědět 11.10.2015 22:05
Avatar
jt.e
Člen
Avatar
Odpovídá na Jakub Šárník
jt.e:

spíš se tady řeší tohle:

String a = new String(String);

jinak, tady máš ještě jeden kód:

class Program
{
    static void Main(string[] args)
    {
        string s = "ssss";
        string n = s;

        Console.WriteLine(GetPointer(ref s));
        Console.WriteLine(GetPointer(ref n));


        Console.ReadKey();
    }

    static long GetPointer(ref string s)
    {
        IntPtr p = Marshal.StringToCoTaskMemUni(s);
        return p.ToInt64();
    }
}
 
Nahoru Odpovědět 11.10.2015 22:20
Avatar
Jan Vargovský
Redaktor
Avatar
Jan Vargovský:

Nějak mi uniká pointa o čem se tu bavíte.

jt.e Máš tušení co dělá ten tvůj poslední kód? Resp. co si myslíš, že má dělat.

 
Nahoru Odpovědět 11.10.2015 22:23
Avatar
jt.e
Člen
Avatar
Odpovídá na Jan Vargovský
jt.e:

Ne ten poslední je blbě, máš pravdu.

 
Nahoru Odpovědět 11.10.2015 22:30
Avatar
jt.e
Člen
Avatar
Odpovídá na Jan Vargovský
jt.e:

Dá se udělat v c# pointer na String?

 
Nahoru Odpovědět 11.10.2015 22:33
Avatar
jt.e
Člen
Avatar
Odpovídá na Jan Vargovský
jt.e:

Nějak mi uniká pointa o čem se tu bavíte.

Mě se prostě nezdá toto tvrzení:

Pokud do instance stringu přiřadíš jinej string, tak se string nebude klonovat, ale zkopíruješ jen referenci, jako u každé jiné třídy.

 
Nahoru Odpovědět 11.10.2015 22:37
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na jt.e
Jan Vargovský:

Vše co ti stačí o stringu vědět je to, kde začíná. To je opravdu vše, co ti stačí vědět. Asi tě napadá, jak teda víš, kde ten string končí. Každý string končí nultým znakem ('\0').

Takže, aby ses nedostal někde mimo do paměti, kde nemáš (neměl bys, uvidíš na příkladě, že můžeš mít) přístup, tak si C# uchovává ještě jak velký ten string je. Obě tyto hodnoty se nastavují v dobe inicializace instance a jakákoliv změna stringu vede k zahození staré instance a vytvoření nové.

Každopádně i C# něco dovolí, tak si můžeš upravit jednotlivé znaky na stringu a vše je naprosto safe.

string str = "abc";
unsafe
{
    fixed (char* p = str)
    {
        Console.WriteLine(p[0]); // a
        p[0] = 'x';
        Console.WriteLine(p[0]); // x
        Console.WriteLine(p[1]); // b
        Console.WriteLine(p[2]); // c
        Console.WriteLine(p[3]); // 0
    }
}
Console.WriteLine(str); // xbc

Dá se udělat v c# pointer na String?

Ano.

Pokud do instance stringu přiřadíš jinej string, tak se string nebude klonovat, ale zkopíruješ jen referenci, jako u každé jiné třídy.

Snad stačí kousek kódu jako ukázka, že se fakt kopíruje jen reference. Je to normální třída.

string str = "abc";
string str2 = str;
unsafe
{
    fixed (char* p = str)
    {
        p[0] = 'x';
    }
}
Console.WriteLine(str); // xbc
Console.WriteLine(str2); // xbc
Editováno 11.10.2015 22:49
 
Nahoru Odpovědět  +1 11.10.2015 22:47
Avatar
jt.e
Člen
Avatar
Odpovídá na Jan Vargovský
jt.e:

takže Jakub Šárník měl pravdu :) Omlouvám se, že jsem nevěřil.

 
Nahoru Odpovědět 11.10.2015 23:02
Avatar
jt.e
Člen
Avatar
jt.e:

Jdu študovat Immutable typy :)

 
Nahoru Odpovědět 11.10.2015 23:07
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 39 zpráv z 39.