ගැඹුරු ක්ලෝනකරණ වස්තු


2236

මට මෙවැනි දෙයක් කිරීමට අවශ්‍යයි:

MyObject myObj = GetMyObj(); // Create and fill a new object
MyObject newObj = myObj.Clone();

ඉන්පසු මුල් වස්තුව තුළ පිළිබිඹු නොවන නව වස්තුවෙහි වෙනස්කම් කරන්න.

මට බොහෝ විට මෙම ක්‍රියාකාරිත්වය අවශ්‍ය නොවේ, එබැවින් එය අවශ්‍ය වූ විට, මම නව වස්තුවක් නිර්මාණය කර එක් එක් දේපල තනි තනිව පිටපත් කිරීමට යොමු වී සිටිමි, නමුත් එය සෑම විටම මට වඩා හොඳ හෝ අලංකාර ලෙස හැසිරවීමේ ක්‍රමයක් ඇති බවට හැඟීමක් ඇති කරයි. අවස්ථාව.

මුල් වස්තුවෙහි කිසිදු වෙනසක් නොමැතිව ක්ලෝන කරන ලද වස්තුව වෙනස් කළ හැකි වන පරිදි වස්තුවක් ක්ලෝන කිරීමට හෝ ගැඹුරින් පිටපත් කිරීමට මට හැක්කේ කෙසේද?


81
ප්‍රයෝජනවත් විය හැකිය: "වස්තුවක් පිටපත් කිරීම භයානක දෙයක් වන්නේ ඇයි?" agiledeveloper.com/articles/cloning072002.htm
Pedro77


18
ඔටෝමැපර්
ඩැනියෙල් ලිට්ල්

3
ඔබේ විසඳුම වඩාත් සංකීර්ණයි, මට එය කියවීම නැති වී ගියා ... හෙහෙහෙ. මම ඩීප් ක්ලෝන් අතුරුමුහුණතක් භාවිතා කරමි. පොදු අතුරුමුහුණත IDeepCloneable <T> Deep T DeepClone (); }
පේද්‍රෝ 77

1
Ed Pedro77 - සිත්ගන්නාසුලු කරුණක් නම්, එම ලිපිය අවසන් වන්නේ cloneපන්තියේ ක්‍රමවේදයක් නිර්මාණය කිරීමට යැයි පැවසුවද , එය සම්මත වන අභ්‍යන්තර, පෞද්ගලික ඉදිකිරීම්කරුවෙකු අමතන්න this. එබැවින් පිටපත් කිරීම භයානක ය [sic], නමුත් ප්‍රවේශමෙන් පිටපත් කිරීම (සහ ලිපිය අනිවාර්යයෙන්ම කියවීම වටී) නොවේ. ; ^)
රූෆින්

Answers:


1726

සම්මත පරිචය වන අතර ICloneableඅතුරු මුහුණත ක්‍රියාත්මක කිරීම ( මෙහි විස්තර කර ඇති බැවින් මම නැවත යථා තත්ත්වයට පත් නොකරමි), මෙන්න මම මීට ටික කලකට පෙර කෝඩ් ප්‍රොජෙක්ට් එකෙන් සොයාගත් අපගේ ගැඹුරු ගැඹුරු ක්ලෝන වස්තු පිටපත් කරන්නෙක් .

වෙනත් තැනක සඳහන් කර ඇති පරිදි, ඔබේ වස්තු අනුක්‍රමික විය යුතුය.

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

/// <summary>
/// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
/// Provides a method for performing a deep copy of an object.
/// Binary Serialization is used to perform the copy.
/// </summary>
public static class ObjectCopier
{
    /// <summary>
    /// Perform a deep Copy of the object.
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T Clone<T>(T source)
    {
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", nameof(source));
        }

        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        IFormatter formatter = new BinaryFormatter();
        Stream stream = new MemoryStream();
        using (stream)
        {
            formatter.Serialize(stream, source);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }
}

අදහස නම් එය ඔබේ වස්තුව අනුක්‍රමික කර නැවුම් වස්තුවක් බවට පත් කිරීමයි. වාසිය නම්, වස්තුවක් ඉතා සංකීර්ණ වූ විට සෑම දෙයක්ම ක්ලෝන කිරීම ගැන ඔබ සැලකිලිමත් විය යුතු නැත.

දීර් extension කිරීමේ ක්‍රම භාවිතා කිරීමත් සමඟ (මුලින් සඳහන් කළ ප්‍රභවයෙන් ද):

ඔබ C # 3.0 හි නව දිගු කිරීමේ ක්‍රම භාවිතා කිරීමට කැමති නම්, පහත අත්සන ඇති ක්‍රමය වෙනස් කරන්න:

public static T Clone<T>(this T source)
{
   //...
}

දැන් ක්‍රමවේදය ඇමතුම සරලවම බවට පත්වේ objectBeingCloned.Clone();.

සංස්කරණය කරන්න (ජනවාරි 10, 2015) මම මෙය නැවත බැලීමට සිතුවෙමි, මෙය සිදු කිරීම සඳහා මම මෑතකදී (නිව්ටන්සොෆ්ට්) ජේසන් භාවිතා කිරීම ආරම්භ කළෙමි, එය සැහැල්ලු විය යුතු අතර , [අනුක්‍රමික කළ හැකි] ටැග් වල ඉහළ කොටස මග හැරේ. ( සැ.යු @atconway පෞද්ගලික සාමාජිකයන් JSON ක්රමය භාවිතා ඉවත්කල යුතු නොවන බව අදහස් පෙන්වා දී ඇත)

/// <summary>
/// Perform a deep Copy of the object, using Json as a serialisation method. NOTE: Private members are not cloned using this method.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T CloneJson<T>(this T source)
{            
    // Don't serialize a null object, simply return the default for that object
    if (Object.ReferenceEquals(source, null))
    {
        return default(T);
    }

    // initialize inner objects individually
    // for example in default constructor some list property initialized with some values,
    // but in 'source' these items are cleaned -
    // without ObjectCreationHandling.Replace default constructor values will be added to result
    var deserializeSettings = new JsonSerializerSettings {ObjectCreationHandling = ObjectCreationHandling.Replace};

    return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}

24
stackoverflow.com/questions/78536/cloning-objects-in-c/… ඉහත කේතයට සබැඳියක් ඇත [සහ තවත් එවැනි ක්‍රියාත්මක කිරීම් දෙකක් සඳහන් කරයි, ඉන් එකක් මගේ සන්දර්භය තුළ වඩාත් යෝග්‍ය වේ]
රූබන් බාර්ටෙලින්ක්

102
අනුක්‍රමිකකරණය / ආශ්‍රිතකරණයට අවශ්‍ය නොවන සැලකිය යුතු පොදු කාර්යයක් ඇතුළත් වේ. C # හි ICloneable අතුරුමුහුණත සහ .MemberWise () ක්ලෝන ක්‍රම බලන්න.
3Dave

19
Av ඩේවිඩ්, ප්‍රදානය කර ඇත, නමුත් වස්තූන් සැහැල්ලු නම් සහ එය භාවිතා කරන විට කාර්ය සාධනය ඔබේ අවශ්‍යතාවන්ට වඩා වැඩි නොවේ නම් එය ප්‍රයෝජනවත් ඉඟියකි. මම එය විශාල දත්ත ප්‍රමාණයක් ලූපයක් සමඟ තීව්‍ර ලෙස භාවිතා කර නැති බව මම පිළිගනිමි, නමුත් මම කිසි විටෙකත් එක කාර්ය සාධනයක් ගැන දැක නැත.
johnc

16
M අමීර්: ඇත්ත වශයෙන්ම, නැත: typeof(T).IsSerializableද වර්ගය [Serializable]ගුණාංගය සමඟ සලකුණු කර ඇත්නම් සත්‍ය වේ. එයට ISerializableඅතුරු මුහුණත ක්‍රියාත්මක කිරීමට අවශ්‍ය නැත .
ඩැනියෙල් ගෙහ්රිගර්

11
මෙම ක්‍රමය ප්‍රයෝජනවත් වන අතර මම එය බොහෝ විට භාවිතා කර ඇති බව සඳහන් කිරීමට සිතුවෙමි, එය කිසිසේත්ම මධ්‍යම භාරය සමඟ නොගැලපේ - එබැවින් ඔබ අනුකූලතාවයක් අවශ්‍ය කේතයක් ලියන්නේ දැයි විමසිල්ලෙන් සිටින්න. ද්විමය ෆෝමැටර් පුද්ගලික ක්ෂේත්‍ර වෙත ප්‍රවේශ වන අතර එමඟින් අර්ධ විශ්වාසනීය පරිසරයන් සඳහා පෙරනිමි අවසර පත්‍රයේ ක්‍රියා කළ නොහැක. ඔබට වෙනත් අනුක්‍රමික යන්ත්‍රයක් උත්සාහ කළ හැකිය, නමුත් පැමිණෙන වස්තුව පුද්ගලික ක්ෂේත්‍ර මත රඳා පවතී නම් ක්ලෝනය පරිපූර්ණ නොවන බව ඔබේ අමතන්නා දැන සිටින බවට වග බලා ගන්න.
ඇලෙක්ස් නොර්ක්ලිෆ්

300

බොහෝ දුරට ප්‍රාථමික හා ලැයිස්තු වල ඉතා සරල වස්තු සඳහා මට ක්ලෝනරයක් අවශ්‍ය විය. ඔබේ වස්තුව JSON අනුක්‍රමික කළ හැකි කොටුවෙන් පිටත තිබේ නම් මෙම ක්‍රමය මඟින් උපක්‍රමය කරනු ඇත. මේ සඳහා ක්ලෝන කරන ලද පන්තියේ අතුරු මුහුණත් වෙනස් කිරීම හෝ ක්‍රියාත්මක කිරීම අවශ්‍ය නොවේ, JSON.NET වැනි JSON අනුක්‍රමික යන්ත්‍රයක් පමණි.

public static T Clone<T>(T source)
{
    var serialized = JsonConvert.SerializeObject(source);
    return JsonConvert.DeserializeObject<T>(serialized);
}

එසේම, ඔබට මෙම දිගු කිරීමේ ක්‍රමය භාවිතා කළ හැකිය

public static class SystemExtension
{
    public static T Clone<T>(this T source)
    {
        var serialized = JsonConvert.SerializeObject(source);
        return JsonConvert.DeserializeObject<T>(serialized);
    }
}

13
ද්රාවණ ෆෝමැටර් විසඳුමට වඩා ද්‍රාවණය වේගවත් වේ .NET අනුක්‍රමික කාර්ය සාධන සංසන්දනය
එස්කාර්

3
මේ සඳහා ස්තූතියි. C # සඳහා මොන්ගෝ ඩීබී ධාවක සමඟ නැව්ගත කරන BSON අනුක්‍රමිකකරණය සමඟ එකම දේ කිරීමට මට හැකි විය.
මාර්ක් ඊවර්

3
මෙය මට හොඳම ක්‍රමයයි, කෙසේ වෙතත්, මම භාවිතා කළ Newtonsoft.Json.JsonConvertනමුත් එය
පියරේ

1
මේ සඳහා වැඩ කිරීමට වස්තුව ක්ලෝන කිරීමට දැනටමත් සඳහන් කර ඇති පරිදි අනුක්‍රමික විය යුතුය - මෙයින් අදහස් කරන්නේ එය රවුම් පරායත්තතා නොතිබිය හැකි බවයි
රේඩෝමීට්

2
බොහෝ ක්‍රමලේඛන භාෂාවල ක්‍රියාත්මක කිරීම ක්‍රියාත්මක කළ හැකි බැවින් මෙය හොඳම විසඳුම යැයි මම සිතමි.
mr5

179

භාවිතා නොකරන ලෙස හේතුව ICloneable වේ නොහැකි එය Generic බලපත්රය යටතේ අවසර ලබා ඇත අතුරු මුහුණත නැති නිසා. එය භාවිතා නොකිරීමට හේතුව එය අපැහැදිලි බැවිනි. ඔබට නොගැඹුරු හෝ ගැඹුරු පිටපතක් ලැබේද යන්න එයින් පැහැදිලි නොවේ; එය ක්‍රියාත්මක කරන්නා සතු ය.

ඔව්, MemberwiseCloneනොගැඹුරු පිටපතක් සාදයි, නමුත් ප්‍රතිවිරුද්ධ MemberwiseCloneදෙය නොවේ Clone; එය සමහර විට DeepCloneනොපවතිනු ඇත. ඔබ වස්තුවක් එහි ICloneable අතුරුමුහුණත හරහා භාවිතා කරන විට, යටින් පවතින වස්තුව ක්ලෝන කරන්නේ කුමන ආකාරයේදැයි ඔබට දැනගත නොහැක. (තවද XML අදහස් වලින් එය පැහැදිලි නොවනු ඇත, මන්ද ඔබට වස්තුවේ ක්ලෝන ක්‍රමයට වඩා අතුරු මුහුණත් අදහස් ලැබෙනු ඇත.)

මම සාමාන්‍යයෙන් කරන්නේ Copyමට අවශ්‍ය දේ කරන ක්‍රමවේදයක් සකස් කිරීමයි .


ICloneable අපැහැදිලි ලෙස සලකන්නේ මන්දැයි මට පැහැදිලි නැත. ශබ්දකෝෂය (Of T, U) වැනි වර්ගයක් ලබා දී ඇති විට, ICloneable.Clone විසින් නව ශබ්දකෝෂය එකම T හා U අඩංගු ස්වාධීන ශබ්දකෝෂයක් බවට පත් කිරීම සඳහා ගැඹුරු හා නොගැඹුරු පිටපත් කිරීමක් අවශ්‍ය වේ යැයි මම බලාපොරොත්තු වෙමි (ව්‍යුහාත්මක අන්තර්ගතයන්, සහ / හෝ වස්තු යොමු) මුල් පිටපත ලෙස. කොහෙද අපැහැදිලි? “ස්වයං” ක්‍රමයක් ඇතුළත් වන අයිසෙල්ෆ් (ටී) උරුම කරගත් සාමාන්‍ය අයික්ලෝනබල් (ඔෆ් ටී) වඩා හොඳ වනු ඇති බවට සැකයක් නැත, නමුත් ගැඹුරු එදිරිව නොගැඹුරු ක්ලෝනකරණය පිළිබඳ අපැහැදිලි බවක් මට නොපෙනේ.
සුපර් කැට්

31
ඔබේ උදාහරණය ගැටලුව නිරූපණය කරයි. ඔබට ශබ්දකෝෂයක් ඇතැයි සිතමු <string, පාරිභෝගික>. මෙම සියල්ල ඉවත්කල ශබ්ද කෝෂය ද තිබිය යුතුය එම මුල් ලෙස පාරිභෝගික වස්තූන්, හෝ පිටපත් එම පාරිභෝගික වස්තූන්? එක්කෝ සඳහා සාධාරණ භාවිත අවස්ථා තිබේ. නමුත් ICloneable ඔබට ලැබෙන්නේ කුමන එකක්ද යන්න පැහැදිලි නොකරයි. එය ප්‍රයෝජනවත් නොවන්නේ එබැවිනි.
රයන් ලුන්ඩි

Y කයිරෙලාසා මයික්‍රොසොෆ්ට් එම්එස්ඩීඑන් ලිපියේ ඇත්ත වශයෙන්ම සඳහන් කරන්නේ ඔබ ගැඹුරු හෝ නොගැඹුරු පිටපතක් ඉල්ලන්නේ දැයි නොදැන සිටීමයි.
පොඩි කරන්න

අනුපිටපත් සිට පිළිතුර stackoverflow.com/questions/129389/... පිටපත් දිගුව, ආවර්තනික MembershipClone මත පදනම් විස්තර
මයිකල් Freidgeim

123

මෙහි සම්බන්ධ කර ඇති බොහෝ විකල්පයන් ගැන බොහෝ දේ කියවීමෙන් පසුව සහ මෙම ගැටළුව සඳහා ඇති විය හැකි විසඳුම් වලින් පසුව, සියලු විකල්පයන් ඉයන් පී ගේ සබැඳියෙන් ඉතා හොඳින් සාරාංශ කොට ඇති බව මම විශ්වාස කරමි (අනෙක් සියලුම විකල්පයන් ඒවායේ වෙනස්කම් වේ) සහ හොඳම විසඳුම සපයන්නේ ප්‍රශ්න විවරණ සඳහා Pedro77 හි සබැඳිය .

එබැවින් මම එම යොමු 2 හි අදාළ කොටස් මෙහි පිටපත් කරමි. අපට තිබිය හැකි ආකාරයට:

සී තියුණු වස්තු ක්ලෝන කිරීම සඳහා කළ හැකි හොඳම දේ!

පළමුවෙන්ම හා ප්‍රධාන වශයෙන්, ඒවා සියල්ලම අපගේ විකල්ප වේ:

ප්‍රකාශන ගස් විසින් වේගවත් ගැඹුරු පිටපතක් යන ලිපියේ අනුක්‍රමිකකරණය, පරාවර්තනය සහ ප්‍රකාශන ගස් මගින් ක්ලෝනකරණය සංසන්දනය කරයි.

මා ICloneable තෝරා ගන්නේ ඇයි (එනම් අතින්)

වෙන්කට් සුබ්‍රමනියම් මහතා (මෙහි අතිරික්ත සබැඳිය) ඊට හේතුව විස්තරාත්මකව පැහැදිලි කරයි .

පුද්ගලයා , මොළය සහ නගරය යන වස්තු 3 ක් භාවිතා කරමින් බොහෝ අවස්ථාවන් සඳහා අදාළ වීමට උත්සාහ කරන උදාහරණයක් වටා ඔහුගේ සියලුම ලිපි රවුම් කරයි . අපට පුද්ගලයෙකු ක්ලෝන කිරීමට අවශ්‍යය, එයට තමන්ගේම මොළයක් ඇති නමුත් එකම නගරය ඇත. ඉහත සඳහන් වෙනත් ක්‍රමවලින් ඔබට ලිපිය ගෙන ඒමට හෝ කියවීමට හැකිය.

මෙය ඔහුගේ නිගමනයෙහි තරමක් වෙනස් කළ අනුවාදයයි:

Newපංතියේ නම අනුගමනය කිරීමෙන් වස්තුවක් පිටපත් කිරීම බොහෝ විට විස්තාරණය කළ නොහැකි කේතයකට මග පාදයි. ක්ලෝන භාවිතා කිරීම, මූලාකෘති රටාව යෙදීම මෙය සාක්ෂාත් කර ගැනීම සඳහා වඩා හොඳ ක්‍රමයකි. කෙසේ වෙතත්, C # (සහ ජාවා) හි දක්වා ඇති පරිදි ක්ලෝන භාවිතා කිරීම ද ගැටලු සහගත විය හැකිය. ආරක්ෂිත (පොදු නොවන) පිටපත් සාදන්නෙකු ලබා දීම සහ ක්ලෝන ක්‍රමයෙන් එය ඉල්ලා සිටීම වඩා හොඳය. මෙය අපට වස්තුවක් නිර්මාණය කිරීමේ කර්තව්‍යය පන්තියකටම පැවරීමේ හැකියාව ලබා දෙයි, එමඟින් විස්තීරණතාව ලබා දෙන අතරම ආරක්ෂිත පිටපත් සාදන්නා භාවිතා කරමින් වස්තූන් ආරක්ෂිතව නිර්මාණය කරයි.

මෙම ක්‍රියාවට නැංවීමෙන් කරුණු පැහැදිලි වනු ඇතැයි අපේක්‍ෂා කරමු:

public class Person : ICloneable
{
    private final Brain brain; // brain is final since I do not want 
                // any transplant on it once created!
    private int age;
    public Person(Brain aBrain, int theAge)
    {
        brain = aBrain; 
        age = theAge;
    }
    protected Person(Person another)
    {
        Brain refBrain = null;
        try
        {
            refBrain = (Brain) another.brain.clone();
            // You can set the brain in the constructor
        }
        catch(CloneNotSupportedException e) {}
        brain = refBrain;
        age = another.age;
    }
    public String toString()
    {
        return "This is person with " + brain;
        // Not meant to sound rude as it reads!
    }
    public Object clone()
    {
        return new Person(this);
    }
    
}

දැන් සලකා බලන්න පුද්ගලයකුගෙන් පන්තියක් ලබා ගැනීම.

public class SkilledPerson extends Person
{
    private String theSkills;
    public SkilledPerson(Brain aBrain, int theAge, String skills)
    {
        super(aBrain, theAge);
        theSkills = skills;
    }
    protected SkilledPerson(SkilledPerson another)
    {
        super(another);
        theSkills = another.theSkills;
    }

    public Object clone()
    {
        return new SkilledPerson(this);
    }
    public String toString()
    {
        return "SkilledPerson: " + super.toString();
    }
}

ඔබට පහත කේතය ධාවනය කිරීමට උත්සාහ කළ හැකිය:

public class User
{
    public static void play(Person p)
    {
        Person another = (Person) p.clone();
        System.out.println(p);
        System.out.println(another);
    }
    public static void main(String[] args)
    {
        Person sam = new Person(new Brain(), 1);
        play(sam);
        SkilledPerson bob = new SkilledPerson(new SmarterBrain(), 1, "Writer");
        play(bob);
    }
}

නිපදවන නිමැවුම වනුයේ:

This is person with Brain@1fcc69
This is person with Brain@253498
SkilledPerson: This is person with SmarterBrain@1fef6f
SkilledPerson: This is person with SmarterBrain@209f4e

අප වස්තු ගණන ගණනය කරන්නේ නම්, මෙහි ක්‍රියාත්මක කර ඇති ක්ලෝනය මඟින් වස්තූන් ගණන නිවැරදිව ගණනය කරනු ඇති බව නිරීක්ෂණය කරන්න.


6
ICloneableමහජන සාමාජිකයින් සඳහා භාවිතා නොකිරීමට MS නිර්දේශ කරයි. "ක්ලෝන අමතන්නන්ට පුරෝකථනය කළ හැකි ක්ලෝනකරණ මෙහෙයුමක් සිදුකරන ක්‍රමය මත රඳා පැවතිය නොහැකි බැවින්, පොදු ඒපීඅයි වල ICloneable ක්‍රියාත්මක නොකිරීමට අපි නිර්දේශ කරමු." msdn.microsoft.com/en-us/library/… කෙසේ වෙතත්, ඔබගේ සම්බන්ධිත ලිපියේ වෙන්කට් සුබ්‍රමනියම් විසින් ලබා දී ඇති පැහැදිලි කිරීම මත පදනම්ව , ICloneable වස්තූන්ගේ නිර්මාතෘවරුන්ට ගැඹුරක් ඇති තාක් කල් මෙම තත්වය තුළ භාවිතා කිරීම අර්ථවත් යැයි මම සිතමි. ගැඹුරු එදිරිව නොගැඹුරු පිටපත් විය යුතු ගුණාංග පිළිබඳ අවබෝධය (එනම් ගැඹුරු පිටපත් මොළය, නොගැඹුරු පිටපත නගරය)
BateTech

පළමුවෙන්ම, මම මෙම මාතෘකාව පිළිබඳ විශේෂ expert යෙකුගෙන් (පොදු API) දුරස්ව සිටිමි. එම්එස් ප්‍රකාශය බොහෝ අර්ථවත් යැයි මම වරක් සිතමි . ඒපීඅයි භාවිතා කරන්නන්ට එතරම් ගැඹුරු අවබෝධයක් ඇතැයි සිතීම ආරක්ෂිත යැයි මම නොසිතමි . එබැවින්, එය පොදු API එකක ක්‍රියාත්මක කිරීම අර්ථවත් වන්නේ එය භාවිතා කිරීමට යන ඕනෑම කෙනෙකුට එය සැබවින්ම වැදගත් නොවේ නම් පමණි. මම හිතන්නේ යම් ආකාරයක යූඑම්එල් එකක් තිබීම පැහැදිලිවම සෑම දේපලකම වෙනස හඳුනා ගැනීම උපකාරී වේ. නමුත් මම වැඩි අත්දැකීම් ඇති අයෙකුගෙන් අසා දැන ගැනීමට කැමතියි. : P
cregox

ඔබට CGbR ක්ලෝන් උත්පාදක යන්ත්රය භාවිතා කර කේතය අතින් ලිවීමකින් තොරව සමාන ප්රති result ලයක් ලබා ගත හැකිය.
ටොක්සැන්ට්‍රන්

අතරමැදි භාෂාව ක්‍රියාත්මක කිරීම ප්‍රයෝජනවත් වේ
මයිකල් ෆ්‍රයිඩ්ජිම්


84

මම කැමතියි ක්ලෝනයකට පිටපත් සාදන්නෙකුට. අභිප්රාය වඩාත් පැහැදිලිය.


5
.නෙට් හි පිටපත් සාදන්නන් නොමැත.
පොප් කැටලින්

48
එය නිසැකවම: නව MyObject (objToCloneFrom) පරාමිතියක් ලෙස වස්තුව ක්ලෝන කිරීමට ගෙන යන ctor එකක් ප්‍රකාශ කරන්න.
නික්

30
එය එකම දෙයක් නොවේ. ඔබ එය සෑම පන්තියකටම අතින් එකතු කළ යුතු අතර, ඔබ ගැඹුරු පිටපතක් ලබා ගන්නේදැයි ඔබ නොදනී.
ඩේව් වැන් ඩෙන් අයින්ඩේ

15
පිටපත් ctor සඳහා +1. සෑම වර්ගයකම වස්තුවක් සඳහා ඔබ විසින් ක්ලෝන () ශ්‍රිතයක් අතින් ලිවිය යුතු අතර, ඔබේ පන්ති ධූරාවලියට මට්ටම් කිහිපයක් ගැඹුරට පැමිණි විට වාසනාව.
ග්‍රාන්ට්

3
පිටපත් සාදන්නන් සමඟ ඔබට ධූරාවලිය අහිමි වේ. agiledeveloper.com/articles/cloning072002.htm
විල්

42

සියලුම පොදු දේපල පිටපත් කිරීම සඳහා සරල දිගු කිරීමේ ක්‍රමය. ඕනෑම වස්තුවක් සඳහා ක්‍රියා කරන අතර පන්තිය වීමට අවශ්‍ය නොවේ[Serializable] . වෙනත් ප්‍රවේශ මට්ටමක් සඳහා දීර් extended කළ හැකිය.

public static void CopyTo( this object S, object T )
{
    foreach( var pS in S.GetType().GetProperties() )
    {
        foreach( var pT in T.GetType().GetProperties() )
        {
            if( pT.Name != pS.Name ) continue;
            ( pT.GetSetMethod() ).Invoke( T, new object[] 
            { pS.GetGetMethod().Invoke( S, null ) } );
        }
    };
}

15
මෙය අවාසනාවකට මෙන් දෝෂ සහිතය. එය objectOne.MyProperty = objectTwo.MyProperty ඇමතීමට සමාන වේ (එනම්, එය යොමු කිරීම හරහා පිටපත් කරනු ඇත). එය ගුණාංගවල අගයන් ක්ලෝන නොකරනු ඇත.
ඇලෙක්ස් නොර්ක්ලිෆ්

1
ඇලෙක්ස් නොර්ක්ලිෆ් වෙත: ප්‍රශ්න කතුවරයා “එක් එක් දේපල පිටපත් කිරීම” ගැන විමසා පසුව ක්ලෝන කිරීම. බොහෝ අවස්ථාවන්හීදී දේපලවල අනුපිටපත් කිරීම අවශ්‍ය නොවේ.
කොන්ස්ටන්ටින් සලවාටෝව්

1
මම හිතන්නේ මෙම ක්‍රමය භාවිතා කිරීම ගැන නමුත් පුනරාවර්තනය සමඟ. එබැවින් දේපලක වටිනාකම යොමු කිරීමක් නම්, නව වස්තුවක් නිර්මාණය කර නැවත CopyTo අමතන්න. මට එක ගැටළුවක් පෙනේ, භාවිතා කරන සියලුම පන්ති වලට පරාමිතීන් නොමැතිව ඉදිකිරීම්කරුවෙකු සිටිය යුතුය. කවුරුහරි දැනටමත් මෙය උත්සාහ කර තිබේද? ඩේටා රෝව් සහ ඩේටා ටේබල් වැනි .net පංති අඩංගු ගුණාංග සමඟ මෙය සැබවින්ම ක්‍රියා කරයිදැයි මම කල්පනා කරමි.
කොරියු

33

මම දැන් CloneExtensionsපුස්තකාල ව්‍යාපෘතියක් නිර්මාණය කර ඇත්තෙමි . ප්‍රකාශන ගස් ධාවන කාල කේත සම්පාදනය මඟින් ජනනය කරන ලද සරල පැවරුම් මෙහෙයුම් භාවිතා කරමින් එය වේගවත් ගැඹුරු ක්ලෝනයක් සිදු කරයි.

එය භාවිතා කරන්නේ කෙසේද?

ක්ෂේත්‍ර සහ දේපල අතර පැවරුම් තානයකින් ඔබේම Cloneහෝ Copyක්‍රමවේදයන් ලිවීම වෙනුවට ප්‍රකාශන ගස භාවිතා කරමින් වැඩසටහන එය ඔබම කර ගන්න. GetClone<T>()විස්තාරණ ක්‍රමයක් ලෙස සලකුණු කර ඇති ක්‍රමය ඔබේ අවස්ථාවෙහිදී එය ඇමතීමට ඉඩ දෙයි:

var newInstance = source.GetClone();

ඔබ පිටපත් කළ යුතු දේ තෝරා ගත හැකිය sourceකිරීමට newInstanceභාවිතා CloningFlagsනිඛිල:

var newInstance 
    = source.GetClone(CloningFlags.Properties | CloningFlags.CollectionItems);

ක්ලෝන කළ හැක්කේ කුමක් ද?

  • ප්‍රාථමික (int, uint, byte, double, char, etc.), දන්නා වෙනස් කළ නොහැකි වර්ග (DateTime, TimeSpan, String) සහ නියෝජිතයින් (Action, Func, ආදිය ඇතුළුව)
  • නුසුදුසු
  • ටී [] අරා
  • සාමාන්‍ය පන්ති සහ ව්‍යුහයන් ඇතුළුව අභිරුචි පන්ති සහ ව්‍යුහයන්.

පහත සඳහන් පංති / ව්‍යුහ සාමාජිකයන් අභ්‍යන්තරව ක්ලෝන කරනු ලැබේ:

  • කියවිය හැකි ක්ෂේත්‍ර නොව පොදු වටිනාකම්
  • ලබා ගැනීම සහ සැකසීම යන දෙකම සහිත පොදු දේපලවල වටිනාකම්
  • ICollection ක්‍රියාත්මක කරන වර්ග සඳහා එකතු කිරීමේ අයිතම

එය කෙතරම් වේගවත්ද?

විසඳුම වේගවත් වන අතර පරාවර්තනය වේ, මන්ද සාමාජිකයින්ගේ තොරතුරු එක් වරක් පමණක් රැස් කර ගත යුතු අතර, GetClone<T>ලබා දී ඇති වර්ගය සඳහා පළමු වරට භාවිතා කිරීමට පෙර T.

ඔබ එකම වර්ගයේ අවස්ථා කිහිපයක් ක්ලෝන කරන විට එය අනුක්‍රමිකකරණය පදනම් කරගත් විසඳුමට වඩා වේගවත් වේ T.

සහ තවත්...

ප්‍රලේඛනය මත ජනනය කරන ලද ප්‍රකාශන ගැන වැඩිදුර කියවන්න .

නියැදි ප්‍රකාශන නිදොස් කිරීමේ ලැයිස්තුගත කිරීම List<int>:

.Lambda #Lambda1<System.Func`4[System.Collections.Generic.List`1[System.Int32],CloneExtensions.CloningFlags,System.Collections.Generic.IDictionary`2[System.Type,System.Func`2[System.Object,System.Object]],System.Collections.Generic.List`1[System.Int32]]>(
    System.Collections.Generic.List`1[System.Int32] $source,
    CloneExtensions.CloningFlags $flags,
    System.Collections.Generic.IDictionary`2[System.Type,System.Func`2[System.Object,System.Object]] $initializers) {
    .Block(System.Collections.Generic.List`1[System.Int32] $target) {
        .If ($source == null) {
            .Return #Label1 { null }
        } .Else {
            .Default(System.Void)
        };
        .If (
            .Call $initializers.ContainsKey(.Constant<System.Type>(System.Collections.Generic.List`1[System.Int32]))
        ) {
            $target = (System.Collections.Generic.List`1[System.Int32]).Call ($initializers.Item[.Constant<System.Type>(System.Collections.Generic.List`1[System.Int32])]
            ).Invoke((System.Object)$source)
        } .Else {
            $target = .New System.Collections.Generic.List`1[System.Int32]()
        };
        .If (
            ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(Fields)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(Fields)
        ) {
            .Default(System.Void)
        } .Else {
            .Default(System.Void)
        };
        .If (
            ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(Properties)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(Properties)
        ) {
            .Block() {
                $target.Capacity = .Call CloneExtensions.CloneFactory.GetClone(
                    $source.Capacity,
                    $flags,
                    $initializers)
            }
        } .Else {
            .Default(System.Void)
        };
        .If (
            ((System.Byte)$flags & (System.Byte).Constant<CloneExtensions.CloningFlags>(CollectionItems)) == (System.Byte).Constant<CloneExtensions.CloningFlags>(CollectionItems)
        ) {
            .Block(
                System.Collections.Generic.IEnumerator`1[System.Int32] $var1,
                System.Collections.Generic.ICollection`1[System.Int32] $var2) {
                $var1 = (System.Collections.Generic.IEnumerator`1[System.Int32]).Call $source.GetEnumerator();
                $var2 = (System.Collections.Generic.ICollection`1[System.Int32])$target;
                .Loop  {
                    .If (.Call $var1.MoveNext() != False) {
                        .Call $var2.Add(.Call CloneExtensions.CloneFactory.GetClone(
                                $var1.Current,
                                $flags,


                         $initializers))
                } .Else {
                    .Break #Label2 { }
                }
            }
            .LabelTarget #Label2:
        }
    } .Else {
        .Default(System.Void)
    };
    .Label
        $target
    .LabelTarget #Label1:
}

}

c # කේතය අනුගමනය කිරීම හා සමාන අර්ථයක් ඇත්තේ කුමක්ද:

(source, flags, initializers) =>
{
    if(source == null)
        return null;

    if(initializers.ContainsKey(typeof(List<int>))
        target = (List<int>)initializers[typeof(List<int>)].Invoke((object)source);
    else
        target = new List<int>();

    if((flags & CloningFlags.Properties) == CloningFlags.Properties)
    {
        target.Capacity = target.Capacity.GetClone(flags, initializers);
    }

    if((flags & CloningFlags.CollectionItems) == CloningFlags.CollectionItems)
    {
        var targetCollection = (ICollection<int>)target;
        foreach(var item in (ICollection<int>)source)
        {
            targetCollection.Add(item.Clone(flags, initializers));
        }
    }

    return target;
}

ඔබ ඔබේම Cloneක්‍රමයක් ලියන්නේ කෙසේද යන්නට සමාන List<int>නොවේද?


2
මෙය නුජෙට් වෙත ලැබීමට ඇති අවස්ථා මොනවාද? එය හොඳම විසඳුම ලෙස පෙනේ. එය NClone සමඟ සැසඳෙන්නේ කෙසේද?
පොඩි කරන්න

මම හිතන්නේ මෙම පිළිතුර තවත් වාර ගණනක් ඉහළ නැංවිය යුතුයි. ICloneable අතින් ක්‍රියාත්මක කිරීම වෙහෙසකර හා දෝෂ සහිත වන අතර, කාර්ය සාධනය වැදගත් නම් පරාවර්තනය හෝ අනුක්‍රමිකකරණය භාවිතා කිරීම මන්දගාමී වන අතර කෙටි කාලයක් තුළ ඔබ වස්තු දහස් ගණනක් පිටපත් කළ යුතුය.
රාත්‍රී කේතය

කිසිසේත් නැත, ඔබ පරාවර්තනය ගැන වැරදියි, ඔබ මෙය නිසි ලෙස හැඹිලිගත කළ යුතුය. මගේ පිළිතුර පහත දැක්වේ stackoverflow.com/a/34368738/4711853
රෝමා බොරෝඩොව්

31

සිල්වර් ලයිට් හි ICloneable භාවිතා කිරීමේදී මට ගැටළු ඇති විය, නමුත් මම seralization අදහසට කැමතියි, මට XML seralize කළ හැකිය, එබැවින් මම මෙය කළෙමි:

static public class SerializeHelper
{
    //Michael White, Holly Springs Consulting, 2009
    //michael@hollyspringsconsulting.com
    public static T DeserializeXML<T>(string xmlData) where T:new()
    {
        if (string.IsNullOrEmpty(xmlData))
            return default(T);

        TextReader tr = new StringReader(xmlData);
        T DocItms = new T();
        XmlSerializer xms = new XmlSerializer(DocItms.GetType());
        DocItms = (T)xms.Deserialize(tr);

        return DocItms == null ? default(T) : DocItms;
    }

    public static string SeralizeObjectToXML<T>(T xmlObject)
    {
        StringBuilder sbTR = new StringBuilder();
        XmlSerializer xmsTR = new XmlSerializer(xmlObject.GetType());
        XmlWriterSettings xwsTR = new XmlWriterSettings();

        XmlWriter xmwTR = XmlWriter.Create(sbTR, xwsTR);
        xmsTR.Serialize(xmwTR,xmlObject);

        return sbTR.ToString();
    }

    public static T CloneObject<T>(T objClone) where T:new()
    {
        string GetString = SerializeHelper.SeralizeObjectToXML<T>(objClone);
        return SerializeHelper.DeserializeXML<T>(GetString);
    }
}

31

ඔබ දැනටමත් ValueInjecter හෝ Automapper වැනි තෙවන පාර්ශවීය යෙදුමක් භාවිතා කරන්නේ නම් , ඔබට මේ වගේ දෙයක් කළ හැකිය:

MyObject oldObj; // The existing object to clone

MyObject newObj = new MyObject();
newObj.InjectFrom(oldObj); // Using ValueInjecter syntax

මෙම ක්‍රමය භාවිතා කිරීමෙන් ඔබට ක්‍රියාත්මක කිරීමට ISerializableහෝ ICloneableඔබේ වස්තු මත අවශ්‍ය නොවේ . MVC / MVVM රටාව සමඟ මෙය පොදු වේ, එබැවින් මෙවැනි සරල මෙවලම් නිර්මාණය කර ඇත.

GitHub හි ValueInjecter ගැඹුරු ක්ලෝනකරණ නියැදිය බලන්න .


26

හොඳම දේ වැනි දිගු කිරීමේ ක්‍රමයක් ක්‍රියාත්මක කිරීමයි

public static T DeepClone<T>(this T originalObject)
{ /* the cloning code */ }

ඉන්පසු විසඳුමේ ඕනෑම තැනක එය භාවිතා කරන්න

var copy = anyObject.DeepClone();

අපට පහත සඳහන් ක්‍රියාත්මක කිරීම් තුන කළ හැකිය:

  1. අනුක්‍රමිකකරණයෙන් (කෙටිම කේතය)
  2. පරාවර්තනයෙන් - 5x වේගවත්
  3. ප්‍රකාශන ගස් අනුව - 20x වේගවත්

සම්බන්ධිත සියලුම ක්‍රම හොඳින් ක්‍රියාත්මක වන අතර ගැඹුරින් පරීක්ෂා කරන ලදී.


ඔබ codeproject.com/Articles/1111658/… හි පළ කර ඇති ප්‍රකාශන ගස් භාවිතයෙන් ක්ලෝනකරණ කේතය .නෙට් රාමුවේ ආරක්‍ෂිත ව්‍යතිරේකයක් සමඟ අසමත් වෙමින් පවතී, මෙහෙයුමට ධාවන කාලය අස්ථාවර කළ හැකිය , එය මූලික වශයෙන් විකෘති ප්‍රකාශන ගසක් නිසා ව්‍යතිරේකයකි එය ක්‍රියාත්මක වන වේලාවේදී Func උත්පාදනය කිරීමට භාවිතා කරයි, කරුණාකර ඔබට යම් විසඳුමක් තිබේදැයි පරීක්ෂා කරන්න. ඇත්ත වශයෙන්ම මා දුටුවේ ගැඹුරු ධූරාවලියක් සහිත සංකීර්ණ වස්තූන් සමඟ පමණක් වන අතර සරල එකක් පහසුවෙන් පිටපත් කළ හැකිය
Mrinal Kamboj

1
ExpressionTree ක්‍රියාත්මක කිරීම ඉතා හොඳයි. එය චක්‍රලේඛ යොමු කිරීම් සහ පෞද්ගලික සාමාජිකයන් සමඟ පවා ක්‍රියා කරයි. කිසිදු ගුණාංගයක් අවශ්‍ය නොවේ. මම සොයාගත් හොඳම පිළිතුර.
N73k

හොඳම පිළිතුර, ඉතා හොඳින් වැඩ කළා, ඔබ මගේ දවස ඉතිරි කළා
ඇඩෙල් මෞරාඩ්

23

කෙටි පිළිතුර නම් ඔබ ICloneable අතුරුමුහුණතෙන් උරුම වී පසුව .clone ශ්‍රිතය ක්‍රියාත්මක කිරීමයි. ක්ලෝන් විසින් සාමාජිකත්ව පිටපතක් කළ යුතු අතර අවශ්‍ය ඕනෑම සාමාජිකයෙකුට ගැඹුරු පිටපතක් සිදු කළ යුතුය. මෙය පුනරාවර්තන මෙහෙයුමකි (ඔබට ක්ලෝන කිරීමට අවශ්‍ය පංතියේ සියලුම සාමාජිකයන් අගය වර්ග හෝ ICloneable ක්‍රියාත්මක කිරීම අවශ්‍ය වන අතර ඔවුන්ගේ සාමාජිකයන් එක්කෝ වටිනාකම් වර්ග හෝ ICloneable ක්‍රියාත්මක කිරීම යනාදිය).

ICloneable භාවිතා කරමින් ක්ලෝනකරණය පිළිබඳ වඩාත් සවිස්තරාත්මක පැහැදිලි කිරීමක් සඳහා, මෙම ලිපිය බලන්න .

මෙම දිගු පිළිතුර "එය රඳා පවතී" වේ. වෙනත් අය සඳහන් කළ පරිදි, ICloneable සඳහා ජනක විද්‍යාව මඟින් සහය නොදක්වන අතර, චක්‍රලේඛ පංති යොමු කිරීම් සඳහා විශේෂ සැලකිල්ලක් අවශ්‍ය වන අතර ඇත්ත වශයෙන්ම සමහරුන් එය සලකන්නේ .NET රාමුවේ “වැරැද්දක්” ලෙස ය. අනුක්‍රමිකකරණ ක්‍රමය රඳා පවතින්නේ ඔබේ වස්තූන් අනුක්‍රමික කළ හැකි ඒවා මත වන අතර ඒවා එසේ නොවිය හැකි අතර ඔබට පාලනය කළ නොහැක. “හොඳම” භාවිතාව පිළිබඳව ප්‍රජාව තුළ තවමත් බොහෝ විවාද පවතී. යථාර්ථය නම්, විසඳුම් කිසිවක් එක ප්‍රමාණයක් ප්‍රමාණවත් නොවන අතර ICloneable වැනි සියලු තත්වයන් සඳහා හොඳම භාවිතයට ගැලපේ.

තවත් විකල්ප කිහිපයක් සඳහා මෙම සංවර්ධකයාගේ කෝනර් ලිපිය බලන්න (ඉයන් වෙත ණය).


1
ICloneable හි සාමාන්‍ය අතුරු මුහුණතක් නොමැත, එබැවින් එම අතුරුමුහුණත භාවිතා කිරීම රෙකමදාරු කරනු නොලැබේ.
කාර්ග්

චක්‍රලේඛ යොමු කිරීම් හැසිරවීමට අවශ්‍ය වන තෙක් ඔබේ විසඳුම ක්‍රියාත්මක වේ, පසුව දේවල් සංකීර්ණ වීමට පටන් ගනී, ගැඹුරු අනුක්‍රමිකකරණය භාවිතයෙන් ගැඹුරු ක්ලෝනකරණය ක්‍රියාත්මක කිරීමට උත්සාහ කිරීම වඩා හොඳය.
පොප් කැටලින්

අවාසනාවකට මෙන්, සෑම වස්තුවක්ම අනුක්‍රමික කළ නොහැකි බැවින් ඔබට සෑම විටම එම ක්‍රමය භාවිතා කළ නොහැක. ඉයන් ගේ සබැඳිය මෙතෙක් ලබා දී ඇති වඩාත්ම සවිස්තරාත්මක පිළිතුරයි.
Zach Burlingame

20
  1. මූලික වශයෙන් ඔබ ICloneable අතුරුමුහුණත ක්‍රියාත්මක කළ යුතු අතර පසුව වස්තු ව්‍යුහ පිටපත් කිරීම අවබෝධ කර ගත යුතුය.
  2. එය සියළුම සාමාජිකයින්ගේ ගැඹුරු පිටපතක් නම්, ඔබ සියලු දරුවන් ද ක්ලෝන කළ හැකි බව රක්ෂණය කළ යුතුය (ඔබ තෝරාගත් විසඳුම හා සම්බන්ධ නොවේ).
  3. සමහර විට ඔබ මෙම ක්‍රියාවලිය තුළ යම් සීමාවන් පිළිබඳව දැනුවත් විය යුතුය, නිදසුනක් ලෙස ඔබ ORM වස්තු පිටපත් කරන්නේ නම් බොහෝ රාමු සැසිවාරයට අනුයුක්ත කර ඇති එක් වස්තුවකට පමණක් ඉඩ දෙන අතර ඔබ මෙම වස්තුවේ ක්ලෝන සෑදිය යුතු නැත, හෝ හැකි නම් ඔබ සැලකිලිමත් විය යුතුය. මෙම වස්තූන් සැසිය ඇමිණීම ගැන.

චියර්ස්.


4
ICloneable හි සාමාන්‍ය අතුරු මුහුණතක් නොමැත, එබැවින් එම අතුරුමුහුණත භාවිතා කිරීම රෙකමදාරු කරනු නොලැබේ.
කාර්ග්

සරල හා සංක්ෂිප්ත පිළිතුරු හොඳම වේ.
ඩේවිඩ්ගුයිටා

17

සංස්කරණය කරන්න: ව්‍යාපෘතිය අත්හිටුවා ඇත

නොදන්නා වර්ග වලට සත්‍ය ක්ලෝනකරණය ඔබට අවශ්‍ය නම් ඔබට වේගවත් ක්ලෝනය දෙස බැලිය හැකිය .

එය ප්‍රකාශන පදනම් කරගත් ක්ලෝනකරණය ද්විමය අනුක්‍රමිකකරණයට වඩා 10 ගුණයක් වේගයෙන් ක්‍රියා කරන අතර සම්පූර්ණ වස්තු ප්‍රස්ථාර අඛණ්ඩතාව පවත්වා ගනී.

එයින් අදහස් වන්නේ: ඔබේ ධූරාවලිය තුළ එකම වස්තුවකට ඔබ කිහිප වතාවක් යොමු කළහොත්, ක්ලෝනයට යොමු වූ එක් අවස්ථාවක් ද ඇත.

ක්ලෝන කරන ලද වස්තූන් සඳහා අතුරුමුහුණත්, ගුණාංග හෝ වෙනත් වෙනස් කිරීමක් අවශ්‍ය නොවේ.


මෙය බෙහෙවින් ප්‍රයෝජනවත් බව පෙනේ
LuckyLikey

සමස්ත පද්ධතියට වඩා, විශේෂයෙන් සංවෘත එකකට වඩා එක් කේත ස්නැප්ෂොට් එකකින් වැඩ කිරීම ආරම්භ කිරීම පහසුය. කිසිම පුස්තකාලයකට එක පහරකින් සියලු ගැටලු විසඳිය නොහැකි බව තේරුම් ගත හැකිය. සමහර ලිහිල් කිරීම් කළ යුතුය.
TarmoPikaro

1
මම ඔබේ විසඳුම අත්හදා බැලූ අතර එය හොඳින් ක්‍රියාත්මක වන බව පෙනේ, ස්තූතියි! මම හිතන්නේ මෙම පිළිතුර තවත් වාර ගණනක් ඉහළ නැංවිය යුතුයි. ICloneable අතින් ක්‍රියාත්මක කිරීම වෙහෙසකර හා දෝෂ සහිත වන අතර, කාර්ය සාධනය වැදගත් නම් පරාවර්තනය හෝ අනුක්‍රමිකකරණය භාවිතා කිරීම මන්දගාමී වන අතර කෙටි කාලයක් තුළ ඔබ වස්තු දහස් ගණනක් පිටපත් කළ යුතුය.
රාත්‍රී කේතය

මම එය උත්සාහ කළ නමුත් එය මට කිසිසේත් සාර්ථක වූයේ නැත. සාමාජික ප්‍රවේශ ව්‍යතිරේකයක් විසි කරයි.
මයිකල් බ්‍රවුන්

.NET හි නවතම අනුවාද සමඟ එය ක්‍රියා නොකරන අතර එය අත්හිටුවා ඇත
මයිකල් සැන්ඩර්

14

දේවල් සරල ලෙස තබා අනෙක් අය සඳහන් කළ පරිදි ඔටෝමැපර් භාවිතා කරන්න , එය එක් වස්තුවක් තවත් වස්තුවකට සිතියම් ගත කිරීම සඳහා සරල කුඩා පුස්තකාලයකි ... එකම වර්ගයේ වස්තුවක් තවත් වර්ගයකට පිටපත් කිරීමට ඔබට අවශ්‍ය වන්නේ කේත පේළි තුනක් පමණි:

MyType source = new MyType();
Mapper.CreateMap<MyType, MyType>();
MyType target = Mapper.Map<MyType, MyType>(source);

ඉලක්කගත වස්තුව දැන් ප්‍රභව වස්තුවේ පිටපතකි. ප්‍රමාණවත් තරම් සරල නොවේද? ඔබේ විසඳුමේ සෑම තැනකම භාවිතා කිරීමට දිගු කිරීමේ ක්‍රමයක් සාදන්න:

public static T Copy<T>(this T source)
{
    T copy = default(T);
    Mapper.CreateMap<T, T>();
    copy = Mapper.Map<T, T>(source);
    return copy;
}

දිගු කිරීමේ ක්‍රමය පහත පරිදි භාවිතා කළ හැකිය:

MyType copy = source.Copy();

මෙය සමඟ ප්‍රවේශම් වන්න, එය ඉතා දුර්වල ලෙස ක්‍රියා කරයි. මම ජෝන්ක් පිළිතුරට මාරුවීම අවසන් කළ අතර එය මේ තරම් කෙටි වන අතර වඩා හොඳ කාර්යයක් ඉටු කරයි.
ඇගෝරිලා

1
මෙය සිදු කරන්නේ නොගැඹුරු පිටපතක් පමණි.
N73k

11

.NET එකක් ජය ගැනීම සඳහා මම මෙය ඉදිරිපත් කළෙමි අඩුපාඩුවක් මඟහරවා ගැනීම සඳහා අතින් ගැඹුරු පිටපත් ලැයිස්තුවක් <T>.

මම මෙය භාවිතා කරමි:

static public IEnumerable<SpotPlacement> CloneList(List<SpotPlacement> spotPlacements)
{
    foreach (SpotPlacement sp in spotPlacements)
    {
        yield return (SpotPlacement)sp.Clone();
    }
}

තවත් තැනක:

public object Clone()
{
    OrderItem newOrderItem = new OrderItem();
    ...
    newOrderItem._exactPlacements.AddRange(SpotPlacement.CloneList(_exactPlacements));
    ...
    return newOrderItem;
}

මෙය සිදු කරන ඔනෙලයිනර් සමඟ පැමිණීමට මම උත්සාහ කළෙමි, නමුත් එය කළ නොහැක්කකි, නිර්නාමික ක්‍රම කුට්ටි තුළ අස්වැන්න වැඩ නොකිරීම නිසා.

වඩා හොඳ තවමත්, සාමාන්‍ය ලැයිස්තුව <T> ක්ලෝනර් භාවිතා කරන්න:

class Utility<T> where T : ICloneable
{
    static public IEnumerable<T> CloneList(List<T> tl)
    {
        foreach (T t in tl)
        {
            yield return (T)t.Clone();
        }
    }
}

10

ප්‍රශ්නය - මම මෙම පිළිතුර තෝරා ගන්නේ ඇයි?

  • ඔබට වේගවත්ම වේගය අවශ්‍ය නම් මෙම පිළිතුර තෝරන්න .NET හැකියාව ඇත.
  • ඔබට ඉතා පහසුවෙන් ක්ලෝන කිරීමේ ක්‍රමයක් අවශ්‍ය නම් මෙම පිළිතුර නොසලකා හරින්න.

වෙනත් වචන වලින් කිවහොත්, ඔබට නිවැරදි කිරීමට අවශ්‍ය කාර්ය සාධන බාධකයක් නොමැති නම් වෙනත් පිළිතුරක් සමඟ යන්න, ඔබට එය පැතිකඩකින් ඔප්පු කළ හැකිය .

වෙනත් ක්‍රමවලට වඩා 10x වේගවත්

ගැඹුරු ක්ලෝනයක් සිදු කිරීමේ පහත ක්‍රමය නම්:

  • අනුක්‍රමිකකරණය / ආශ්‍රිතකරණයට සම්බන්ධ ඕනෑම දෙයකට වඩා 10x වේගවත්;
  • න්‍යායාත්මක උපරිම වේගයට ආසන්නව ඉතා අලංකාරයි .නෙට් හැකියාව ඇත.

ක්‍රමය ...

අවසාන වේගය සඳහා, ගැඹුරු පිටපතක් කිරීමට ඔබට නෙස්ටඩ් සාමාජික වයිස් ක්ලෝන් භාවිතා කළ හැකිය . එය අගය ව්‍යුහයක් පිටපත් කිරීමට සමාන වේගයකින් යුක්ත වන අතර (අ) පරාවර්තනය හෝ (ආ) අනුක්‍රමිකකරණයට වඩා වේගවත් වේ (මෙම පිටුවේ වෙනත් පිළිතුරු වල විස්තර කර ඇති පරිදි).

ගැඹුරු පිටපතක් සඳහා ඔබ නෙස්ටඩ් සාමාජික ක්ලෝන් භාවිතා කරන්නේ නම් , ඔබ පන්තියේ සෑම කැදැලි මට්ටමක් සඳහාම නොගැඹුරු කොපියක් අතින් ක්‍රියාත්මක කළ යුතු අතර සම්පූර්ණ ක්ලෝනයක් නිර්මාණය කිරීම සඳහා කියූ ෂැලෝකොපි ක්‍රම සියල්ලම හඳුන්වන ඩීප්කොපි ය. මෙය සරලයි: සම්පූර්ණ පේළි කිහිපයක් පමණි, පහත නිරූපණ කේතය බලන්න.

ක්ලෝන 100,000 ක් සඳහා සාපේක්ෂ කාර්යසාධන වෙනස පෙන්වන කේතයේ ප්‍රතිදානය මෙන්න:

  • කැදැලි ව්‍යුහයන් මත නෙස්ටඩ් සාමාජික වයිස් ක්ලෝන් සඳහා තත්පර 1.08 ක්
  • කැදැලි පංති සඳහා නෙස්ටඩ් සාමාජික ක්ලෝන් සඳහා තත්පර 4.77 ක්
  • තත්පර 39.93 ක අනුක්‍රමිකකරණය / ඩෙසරීකරණය සඳහා

ව්‍යුහයක් පිටපත් කිරීම තරම් වේගයෙන් පන්තියක නෙස්ටඩ් සාමාජික ක්ලෝන් භාවිතා කිරීම, සහ ව්‍යුහයක් පිටපත් කිරීම න්‍යායාත්මක උපරිම වේගයට ආසන්නව පිහිටා ඇත .නෙට් හැකියාව ඇත.

Demo 1 of shallow and deep copy, using classes and MemberwiseClone:
  Create Bob
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Clone Bob >> BobsSon
  Adjust BobsSon details
    BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Elapsed time: 00:00:04.7795670,30000000

Demo 2 of shallow and deep copy, using structs and value copying:
  Create Bob
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Clone Bob >> BobsSon
  Adjust BobsSon details:
    BobsSon.Age=2, BobsSon.Purchase.Description=Toy car
  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:
    Bob.Age=30, Bob.Purchase.Description=Lamborghini
  Elapsed time: 00:00:01.0875454,30000000

Demo 3 of deep copy, using class and serialize/deserialize:
  Elapsed time: 00:00:39.9339425,30000000

MemberwiseCopy භාවිතයෙන් ගැඹුරු පිටපතක් කරන්නේ කෙසේද යන්න තේරුම් ගැනීමට, ඉහත වේලාවන් උත්පාදනය කිරීම සඳහා භාවිතා කළ ආදර්ශන ව්‍යාපෘතිය මෙන්න:

// Nested MemberwiseClone example. 
// Added to demo how to deep copy a reference class.
[Serializable] // Not required if using MemberwiseClone, only used for speed comparison using serialization.
public class Person
{
    public Person(int age, string description)
    {
        this.Age = age;
        this.Purchase.Description = description;
    }
    [Serializable] // Not required if using MemberwiseClone
    public class PurchaseType
    {
        public string Description;
        public PurchaseType ShallowCopy()
        {
            return (PurchaseType)this.MemberwiseClone();
        }
    }
    public PurchaseType Purchase = new PurchaseType();
    public int Age;
    // Add this if using nested MemberwiseClone.
    // This is a class, which is a reference type, so cloning is more difficult.
    public Person ShallowCopy()
    {
        return (Person)this.MemberwiseClone();
    }
    // Add this if using nested MemberwiseClone.
    // This is a class, which is a reference type, so cloning is more difficult.
    public Person DeepCopy()
    {
            // Clone the root ...
        Person other = (Person) this.MemberwiseClone();
            // ... then clone the nested class.
        other.Purchase = this.Purchase.ShallowCopy();
        return other;
    }
}
// Added to demo how to copy a value struct (this is easy - a deep copy happens by default)
public struct PersonStruct
{
    public PersonStruct(int age, string description)
    {
        this.Age = age;
        this.Purchase.Description = description;
    }
    public struct PurchaseType
    {
        public string Description;
    }
    public PurchaseType Purchase;
    public int Age;
    // This is a struct, which is a value type, so everything is a clone by default.
    public PersonStruct ShallowCopy()
    {
        return (PersonStruct)this;
    }
    // This is a struct, which is a value type, so everything is a clone by default.
    public PersonStruct DeepCopy()
    {
        return (PersonStruct)this;
    }
}
// Added only for a speed comparison.
public class MyDeepCopy
{
    public static T DeepCopy<T>(T obj)
    {
        object result = null;
        using (var ms = new MemoryStream())
        {
            var formatter = new BinaryFormatter();
            formatter.Serialize(ms, obj);
            ms.Position = 0;
            result = (T)formatter.Deserialize(ms);
            ms.Close();
        }
        return (T)result;
    }
}

ඉන්පසු, ප්‍රධාන වශයෙන් නිරූපණය අමතන්න:

void MyMain(string[] args)
{
    {
        Console.Write("Demo 1 of shallow and deep copy, using classes and MemberwiseCopy:\n");
        var Bob = new Person(30, "Lamborghini");
        Console.Write("  Create Bob\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
        Console.Write("  Clone Bob >> BobsSon\n");
        var BobsSon = Bob.DeepCopy();
        Console.Write("  Adjust BobsSon details\n");
        BobsSon.Age = 2;
        BobsSon.Purchase.Description = "Toy car";
        Console.Write("    BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
        Console.Write("  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
        Debug.Assert(Bob.Age == 30);
        Debug.Assert(Bob.Purchase.Description == "Lamborghini");
        var sw = new Stopwatch();
        sw.Start();
        int total = 0;
        for (int i = 0; i < 100000; i++)
        {
            var n = Bob.DeepCopy();
            total += n.Age;
        }
        Console.Write("  Elapsed time: {0},{1}\n\n", sw.Elapsed, total);
    }
    {               
        Console.Write("Demo 2 of shallow and deep copy, using structs:\n");
        var Bob = new PersonStruct(30, "Lamborghini");
        Console.Write("  Create Bob\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);
        Console.Write("  Clone Bob >> BobsSon\n");
        var BobsSon = Bob.DeepCopy();
        Console.Write("  Adjust BobsSon details:\n");
        BobsSon.Age = 2;
        BobsSon.Purchase.Description = "Toy car";
        Console.Write("    BobsSon.Age={0}, BobsSon.Purchase.Description={1}\n", BobsSon.Age, BobsSon.Purchase.Description);
        Console.Write("  Proof of deep copy: If BobsSon is a true clone, then adjusting BobsSon details will not affect Bob:\n");
        Console.Write("    Bob.Age={0}, Bob.Purchase.Description={1}\n", Bob.Age, Bob.Purchase.Description);                
        Debug.Assert(Bob.Age == 30);
        Debug.Assert(Bob.Purchase.Description == "Lamborghini");
        var sw = new Stopwatch();
        sw.Start();
        int total = 0;
        for (int i = 0; i < 100000; i++)
        {
            var n = Bob.DeepCopy();
            total += n.Age;
        }
        Console.Write("  Elapsed time: {0},{1}\n\n", sw.Elapsed, total);
    }
    {
        Console.Write("Demo 3 of deep copy, using class and serialize/deserialize:\n");
        int total = 0;
        var sw = new Stopwatch();
        sw.Start();
        var Bob = new Person(30, "Lamborghini");
        for (int i = 0; i < 100000; i++)
        {
            var BobsSon = MyDeepCopy.DeepCopy<Person>(Bob);
            total += BobsSon.Age;
        }
        Console.Write("  Elapsed time: {0},{1}\n", sw.Elapsed, total);
    }
    Console.ReadKey();
}

නැවතත්, ගැඹුරු පිටපතක් සඳහා ඔබ නෙස්ටඩ් සාමාජික ක්ලෝන් භාවිතා කරන්නේ නම් , ඔබ පන්තියේ සෑම කැදැල්ලකටම නොගැඹුරු කොපියක් අතින් ක්‍රියාත්මක කළ යුතු අතර සම්පූර්ණ ක්ලෝනයක් නිර්මාණය කිරීම සඳහා කියූ ෂැලෝකොපි ක්‍රම සියල්ලම හඳුන්වන ඩීප්කොපි ය. මෙය සරලයි: සම්පූර්ණ පේළි කිහිපයක් පමණි, ඉහත ආදර්ශන කේතය බලන්න.

අගය වර්ග එදිරිව යොමු සටහන් වර්ග

වස්තුවක් ක්ලෝන කිරීමේදී " struct " සහ " class " අතර විශාල වෙනසක් ඇති බව සලකන්න :

  • ඔබට " struct " තිබේ නම්, එය අගය වර්ගයක් බැවින් ඔබට එය පිටපත් කළ හැකිය, එවිට අන්තර්ගතය ක්ලෝන කරනු ලැබේ (නමුත් එය නොගැඹුරු ක්ලෝනයක් සාදනුයේ ඔබ මෙම තනතුරේ ශිල්පීය ක්‍රම භාවිතා නොකරන්නේ නම් පමණි).
  • ඔබට " පංතියක් " තිබේ නම්, එය විමර්ශන වර්ගයකි , එබැවින් ඔබ එය පිටපත් කරන්නේ නම්, ඔබ කරන්නේ ඒ සඳහා දර්ශකය පිටපත් කිරීමයි. සත්‍ය ක්ලෝනයක් නිර්මාණය කිරීම සඳහා, ඔබ වඩාත් නිර්මාණශීලී විය යුතු අතර, මතක වර්ගයේ මුල් වස්තුවේ තවත් පිටපතක් නිර්මාණය කරන අගය වර්ග සහ යොමු වර්ග අතර වෙනස්කම් භාවිතා කරන්න .

අගය වර්ග සහ යොමු වර්ග අතර වෙනස්කම් බලන්න .

නිදොස්කරණය සඳහා සහාය වන චෙක්සම්

  • වස්තූන් වැරදියට ක්ලෝන කිරීම ඉතා අපහසු-සිට-පහළට-දෝෂ වලට තුඩු දිය හැකිය. නිෂ්පාදන කේතයේ දී, වස්තුව නිසියාකාරව ක්ලෝන කර ඇත්දැයි දෙවරක් පරීක්ෂා කිරීම සඳහා චෙක්සමයක් ක්‍රියාත්මක කිරීමට මම නැඹුරු වෙමි. මෙම චෙක්සමය මුදා හැරීමේ ආකාරයෙන් ක්‍රියා විරහිත කළ හැකිය.
  • මෙම ක්‍රමය බෙහෙවින් ප්‍රයෝජනවත් බව මට පෙනේ: බොහෝ විට, ඔබට අවශ්‍ය වන්නේ වස්තුවේ කොටස් පමණක් ක්ලෝන කිරීමට මිස සමස්ත දේම නොවේ.

වෙනත් බොහෝ නූල් වලින් බොහෝ නූල් විසන්ධි කිරීමට සැබවින්ම ප්‍රයෝජනවත් වේ

මෙම කේතය සඳහා එක් විශිෂ්ට භාවිතයක් වන්නේ නිෂ්පාදකයා / පාරිභෝගික රටාව ක්‍රියාත්මක කිරීම සඳහා කැදැලි පන්තියක හෝ ව්‍යුහයක් පෝලිම්වලට පෝෂණය කිරීමයි.

  • අපට ඔවුන් සතුව ඇති පන්තියක් වෙනස් කරමින් නූල් එකක් (හෝ වැඩි ගණනක්) තිබිය හැකි අතර පසුව මෙම පන්තියේ සම්පූර්ණ පිටපතක් a ConcurrentQueue .
  • මෙම පංතිවල පිටපත් ඉවතට ගෙන ඒවා සමඟ ගනුදෙනු කිරීමේදී අපට නූල් එකක් (හෝ වැඩි ගණනක්) ඇත.

මෙය ප්‍රායෝගිකව ඉතා හොඳින් ක්‍රියාත්මක වන අතර, නූල් එකක් හෝ වැඩි ගණනකින් (පාරිභෝගිකයින්) බොහෝ නූල් (නිෂ්පාදකයන්) විසන්ධි කිරීමට අපට ඉඩ දෙයි.

මෙම ක්‍රමය ද අන්ධ ලෙස වේගවත් ය: අප කැදැලි ව්‍යුහයන් භාවිතා කරන්නේ නම්, එය කැදැලි පන්ති අනුක්‍රමිකකරණයට / අවපීඩනයට වඩා 35x වේගවත් වන අතර යන්ත්‍රයේ ඇති සියලුම නූල් වලින් ප්‍රයෝජන ගැනීමට අපට ඉඩ සලසයි.

යාවත්කාලීන කරන්න

පෙනෙන ආකාරයට, එක්ස්ප්‍රස්මැපර් ඉහත වැනි අත් කේතීකරණයට වඩා වේගවත්, වේගවත් නොවේ නම්. ඔවුන් පැතිකඩක් සමඟ සංසන්දනය කරන්නේ කෙසේදැයි මට දැකීමට සිදුවනු ඇත.


ඔබ ව්‍යුහයක් පිටපත් කරන්නේ නම් ඔබට නොගැඹුරු පිටපතක් ලැබෙනු ඇත, ගැඹුරු පිටපතක් සඳහා නිශ්චිත ක්‍රියාත්මක කිරීමක් ඔබට අවශ්‍ය විය හැකිය.
ලාස් වී. කාල්සන්

As ලාස් වී. කාල්සන්. ඔව්, ඔබ හරියටම නිවැරදියි, මෙය වඩාත් පැහැදිලි කිරීම සඳහා මම පිළිතුර යාවත්කාලීන කර ඇත. ව්‍යුහයන් සහ පංතිවල ගැඹුරු පිටපත් සෑදීම සඳහා මෙම ක්‍රමය භාවිතා කළ හැකිය . ඇතුළත් කළ ආදර්ශන කේතය එය ක්‍රියාත්මක කළ ආකාරය පෙන්වීමට ඔබට එය ක්‍රියාත්මක කළ හැකිය, එයට ගැඹුරු ක්ලෝනකරණය සඳහා කැදැලි ව්‍යුහයක් සහ කැදැලි පන්තියක් ගැඹුරු ක්ලෝනකරණයට තවත් උදාහරණයක් ඇත.
කොන්ටැන්ගෝ

9

පොදුවේ ගත් කල, ඔබ ICloneable අතුරුමුහුණත ක්‍රියාත්මක කර ක්ලෝනය ඔබම ක්‍රියාත්මක කරයි. C # වස්තූන් තුළ ගොඩනංවන ලද MemberwiseClone ක්‍රමයක් ඇති අතර එය නොගැඹුරු පිටපතක් සිදු කරයි.

ගැඹුරු පිටපතක් සඳහා, එය ස්වයංක්‍රීයව කරන්නේ කෙසේදැයි දැන ගැනීමට ක්‍රමයක් නොමැත.


ICloneable හි සාමාන්‍ය අතුරු මුහුණතක් නොමැත, එබැවින් එම අතුරුමුහුණත භාවිතා කිරීම රෙකමදාරු කරනු නොලැබේ.
කාර්ග්

8

එය පරාවර්තනය තුළින් ද ක්‍රියාත්මක වන බව මම දැක ඇත්තෙමි. මූලික වශයෙන් යම් වස්තුවක සාමාජිකයන් හරහා පුනරාවර්තනය වී ඒවා නිසි ලෙස නව වස්තුවට පිටපත් කරන ක්‍රමයක් තිබුණි. එය විමර්ශන වර්ග හෝ එකතු කිරීම් කරා ළඟා වූ විට මම සිතන්නේ එය පුනරාවර්තන ඇමතුමක් ලබා ගත් බවයි. පරාවර්තනය මිල අධිකයි, නමුත් එය ඉතා හොඳින් ක්‍රියාත්මක විය.


8

ගැඹුරු පිටපත් ක්‍රියාත්මක කිරීමක් මෙන්න:

public static object CloneObject(object opSource)
{
    //grab the type and create a new instance of that type
    Type opSourceType = opSource.GetType();
    object opTarget = CreateInstanceOfType(opSourceType);

    //grab the properties
    PropertyInfo[] opPropertyInfo = opSourceType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);

    //iterate over the properties and if it has a 'set' method assign it from the source TO the target
    foreach (PropertyInfo item in opPropertyInfo)
    {
        if (item.CanWrite)
        {
            //value types can simply be 'set'
            if (item.PropertyType.IsValueType || item.PropertyType.IsEnum || item.PropertyType.Equals(typeof(System.String)))
            {
                item.SetValue(opTarget, item.GetValue(opSource, null), null);
            }
            //object/complex types need to recursively call this method until the end of the tree is reached
            else
            {
                object opPropertyValue = item.GetValue(opSource, null);
                if (opPropertyValue == null)
                {
                    item.SetValue(opTarget, null, null);
                }
                else
                {
                    item.SetValue(opTarget, CloneObject(opPropertyValue), null);
                }
            }
        }
    }
    //return the new item
    return opTarget;
}

2
විමර්ශන වර්ගයේ ගුණාංග නොදන්නා නිසා මෙය සාමාජික ක්ලෝන් ලෙස පෙනේ
sll

1
ඔබට අන්ධ ලෙස වේගවත් කාර්ය සාධනයක් අවශ්‍ය නම්, මෙම ක්‍රියාත්මක කිරීම සඳහා නොයන්න: එය පරාවර්තනය භාවිතා කරයි, එබැවින් එය එතරම් වේගවත් නොවනු ඇත. අනෙක් අතට, "නොමේරූ ප්‍රශස්තිකරණය යනු සියලු නපුරකි", එබැවින් ඔබ පැතිකඩක් ධාවනය කළ පසු කාර්ය සාධනය නොසලකා හරින්න.
කොන්ටැන්ගෝ

1
CreateInstanceOfType යන්න අර්ථ දක්වා නැත?
MonsterMMORPG

එය ඉන්ටර්ජර් මත අසමත් වේ: "ස්ථිතික නොවන ක්‍රමයට ඉලක්කයක් අවශ්‍ය වේ."
බී මහතා

8

විවිධ ව්‍යාපෘති වලදී මගේ සියලු අවශ්‍යතා සපුරාලන ක්ලෝනරයක් මට සොයාගත නොහැකි වූ නිසා, මම ක්ලෝන අවශ්‍යතා සපුරාලීම සඳහා මගේ කේතය අනුවර්තනය කරනවා වෙනුවට වින්‍යාසගත කර විවිධ කේත ව්‍යුහයන්ට අනුවර්තනය කළ හැකි ගැඹුරු ක්ලෝනරයක් නිර්මාණය කළෙමි. එය සාක්ෂාත් කරගනු ලබන්නේ ක්ලෝන කළ යුතු කේතයට විවරණ එකතු කිරීමෙන් හෝ පෙරනිම හැසිරීම ඇති බැවින් ඔබ කේතය අතහැර දමන්න. එය පරාවර්තනය, හැඹිලි ටයිප් කරන අතර වේගවත් තේරීම මත පදනම් වේ . ක්ලෝන කිරීමේ ක්‍රියාවලිය විශාල දත්ත ප්‍රමාණයක් සහ ඉහළ වස්තු ධූරාවලියක් සඳහා ඉතා වේගවත් වේ (වෙනත් පරාවර්තනය / අනුක්‍රමිකකරණය පදනම් කරගත් ඇල්ගොරිතම හා සසඳන විට).

https://github.com/kalisohn/CloneBehave

නූගට් පැකේජයක් ලෙසද ලබා ගත හැකිය: https://www.nuget.org/packages/Clone.Behave/1.0.0

උදාහරණයක් ලෙස: පහත කේතය ගැඹුරු ලිපින ලිපියක් වනු ඇත, නමුත් සිදු කරන්නේ _currentJob ක්ෂේත්‍රයේ නොගැඹුරු පිටපතක් පමණි.

public class Person 
{
  [DeepClone(DeepCloneBehavior.Shallow)]
  private Job _currentJob;      

  public string Name { get; set; }

  public Job CurrentJob 
  { 
    get{ return _currentJob; }
    set{ _currentJob = value; }
  }

  public Person Manager { get; set; }
}

public class Address 
{      
  public Person PersonLivingHere { get; set; }
}

Address adr = new Address();
adr.PersonLivingHere = new Person("John");
adr.PersonLivingHere.BestFriend = new Person("James");
adr.PersonLivingHere.CurrentJob = new Job("Programmer");

Address adrClone = adr.Clone();

//RESULT
adr.PersonLivingHere == adrClone.PersonLivingHere //false
adr.PersonLivingHere.Manager == adrClone.PersonLivingHere.Manager //false
adr.PersonLivingHere.CurrentJob == adrClone.PersonLivingHere.CurrentJob //true
adr.PersonLivingHere.CurrentJob.AnyProperty == adrClone.PersonLivingHere.CurrentJob.AnyProperty //true

7

කේත ජනකය

අතින් ක්‍රියාවට නැංවීම පිළිබඳ අනුක්‍රමිකකරණයේ සිට පරාවර්තනය දක්වා බොහෝ අදහස් අප දැක ඇති අතර CGbR කේත උත්පාදක යන්ත්රය භාවිතයෙන් සම්පූර්ණයෙන්ම වෙනස් ප්‍රවේශයක් යෝජනා කිරීමට මට අවශ්‍යය . උත්පාදක ක්ලෝන ක්‍රමය මතකය සහ CPU කාර්යක්ෂම වන අතර එමඟින් සම්මත ඩේටා කොන්ත්‍රාත් සීරියලයිසර් මෙන් 300x වේගවත් වේ.

ඔබට අවශ්‍ය වන්නේ අර්ධ පන්ති අර්ථ දැක්වීමක් සමඟ වන ICloneableඅතර උත්පාදක යන්ත්රය ඉතිරි දේ කරයි:

public partial class Root : ICloneable
{
    public Root(int number)
    {
        _number = number;
    }
    private int _number;

    public Partial[] Partials { get; set; }

    public IList<ulong> Numbers { get; set; }

    public object Clone()
    {
        return Clone(true);
    }

    private Root()
    {
    }
} 

public partial class Root
{
    public Root Clone(bool deep)
    {
        var copy = new Root();
        // All value types can be simply copied
        copy._number = _number; 
        if (deep)
        {
            // In a deep clone the references are cloned 
            var tempPartials = new Partial[Partials.Length];
            for (var i = 0; i < Partials.Length; i++)
            {
                var value = Partials[i];
                value = value.Clone(true);
                tempPartials[i] = value;
            }
            copy.Partials = tempPartials;
            var tempNumbers = new List<ulong>(Numbers.Count);
            for (var i = 0; i < Numbers.Count; i++)
            {
                var value = Numbers[i];
                tempNumbers.Add(value);
            }
            copy.Numbers = tempNumbers;
        }
        else
        {
            // In a shallow clone only references are copied
            copy.Partials = Partials; 
            copy.Numbers = Numbers; 
        }
        return copy;
    }
}

සටහන: නවතම අනුවාදයේ වඩා ශුන්‍ය චෙක්පත් ඇත, නමුත් වඩා හොඳ අවබෝධයක් සඳහා මම ඒවා අතහැර දැමුවෙමි.


6

මම ඒ වගේ Copyconstructors වලට කැමතියි:

    public AnyObject(AnyObject anyObject)
    {
        foreach (var property in typeof(AnyObject).GetProperties())
        {
            property.SetValue(this, property.GetValue(anyObject));
        }
        foreach (var field in typeof(AnyObject).GetFields())
        {
            field.SetValue(this, field.GetValue(anyObject));
        }
    }

පිටපත් කිරීමට ඔබට තවත් බොහෝ දේ ඇත්නම් ඒවා එකතු කරන්න


6

මෙම ක්‍රමය මට ඇති ගැටලුව විසඳීය:

private static MyObj DeepCopy(MyObj source)
        {

            var DeserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };

            return JsonConvert.DeserializeObject<MyObj >(JsonConvert.SerializeObject(source), DeserializeSettings);

        }

එය මේ ආකාරයට භාවිතා කරන්න: MyObj a = DeepCopy(b);


6

මෙහිදී අනුක්‍රමිකකරණය / ඩෙසරීකරණය පිළිබඳ අවධානය යොමු නොකර මට වැඩ කළ වේගවත් හා පහසු විසඳුමක්.

public class MyClass
{
    public virtual MyClass DeepClone()
    {
        var returnObj = (MyClass)MemberwiseClone();
        var type = returnObj.GetType();
        var fieldInfoArray = type.GetRuntimeFields().ToArray();

        foreach (var fieldInfo in fieldInfoArray)
        {
            object sourceFieldValue = fieldInfo.GetValue(this);
            if (!(sourceFieldValue is MyClass))
            {
                continue;
            }

            var sourceObj = (MyClass)sourceFieldValue;
            var clonedObj = sourceObj.DeepClone();
            fieldInfo.SetValue(returnObj, clonedObj);
        }
        return returnObj;
    }
}

සංස්කරණය කරන්න : අවශ්‍යයි

    using System.Linq;
    using System.Reflection;

මම එය භාවිතා කළ ආකාරය එයයි

public MyClass Clone(MyClass theObjectIneededToClone)
{
    MyClass clonedObj = theObjectIneededToClone.DeepClone();
}

5

මෙම පියවර අනුගමනය කරන්න:

  • නැවත ISelf<T>කියවිය හැකි Selfදේපලක් සහිත දේ නිර්වචනය කරන්න T, සහ ICloneable<out T>, එයින් ව්‍යුත්පන්න වූ ISelf<T>සහ ක්‍රමයක් ඇතුළත් වේ T Clone().
  • සම්මත කළ වර්ගයට වාත්තු කිරීමක් CloneBaseක්‍රියාත්මක කරන වර්ගයක් නිර්වචනය කරන්න. protected virtual generic VirtualCloneMemberwiseClone
  • සෑම ව්‍යුත්පන්න වර්ගයක්ම ක්‍රියාත්මක කළ යුත්තේ VirtualCloneමූලික ක්ලෝන ක්‍රමය අමතා මව් වර්චුවල් ක්ලෝන් ක්‍රමය තවමත් හසුරුවා නැති ව්‍යුත්පන්න වර්ගයේ එම අංග නිසි ලෙස ක්ලෝන කිරීම සඳහා කළ යුතු ඕනෑම දෙයක් කිරීමෙනි.

උපරිම උරුම බහුකාර්යතාව සඳහා, පොදු ක්ලෝනකරණ ක්‍රියාකාරිත්වය නිරාවරණය කරන පන්ති විය යුතු sealedනමුත් ක්ලෝනකරණයේ lack නතාව හැර වෙනත් ආකාරයකින් සමාන වන මූලික පන්තියකින් ව්‍යුත්පන්න විය. පැහැදිලි ක්ලෝන කළ හැකි වර්ගයේ විචල්‍යයන් පසුකරනවා වෙනුවට, වර්ගයේ පරාමිතියක් ගන්න ICloneable<theNonCloneableType>. මෙය ක්ලෝන කළ හැකි ව්‍යුත්පන්නයක් ක්ලෝන කළ හැකි ව්‍යුත්පන්නයක් Fooසමඟ වැඩ කිරීමට අපේක්ෂා කරන චර්යාවකට DerivedFooඉඩ දෙන අතරම ක්ලෝන කළ නොහැකි ව්‍යුත්පන්නයන් නිර්මාණය කිරීමට ද ඉඩ දෙයි Foo.


5

මම හිතන්නේ ඔබට මෙය උත්සාහ කළ හැකිය.

MyObject myObj = GetMyObj(); // Create and fill a new object
MyObject newObj = new MyObject(myObj); //DeepClone it

4

'[Serializable]' සහ '[DataContract]' යන දෙකම සමඟ ක්‍රියා කරන පිළිගත් පිළිතුරේ අනුවාදයක් මම නිර්මාණය කර ඇත්තෙමි. මා එය ලියා ටික කලක් ගතවී ඇත, නමුත් මට නිවැරදිව මතක නම් [DataContract] වෙනත් අනුක්‍රමික යන්ත්‍රයක් අවශ්‍ය විය.

අවශ්ය පද්ධතිය, System.IO, System.Runtime.Serialization, System.Runtime.Serialization.Formatters.Binary, System.Xml ;

public static class ObjectCopier
{

    /// <summary>
    /// Perform a deep Copy of an object that is marked with '[Serializable]' or '[DataContract]'
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T Clone<T>(T source)
    {
        if (typeof(T).IsSerializable == true)
        {
            return CloneUsingSerializable<T>(source);
        }

        if (IsDataContract(typeof(T)) == true)
        {
            return CloneUsingDataContracts<T>(source);
        }

        throw new ArgumentException("The type must be Serializable or use DataContracts.", "source");
    }


    /// <summary>
    /// Perform a deep Copy of an object that is marked with '[Serializable]'
    /// </summary>
    /// <remarks>
    /// Found on http://stackoverflow.com/questions/78536/cloning-objects-in-c-sharp
    /// Uses code found on CodeProject, which allows free use in third party apps
    /// - http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
    /// </remarks>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T CloneUsingSerializable<T>(T source)
    {
        if (!typeof(T).IsSerializable)
        {
            throw new ArgumentException("The type must be serializable.", "source");
        }

        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        IFormatter formatter = new BinaryFormatter();
        Stream stream = new MemoryStream();
        using (stream)
        {
            formatter.Serialize(stream, source);
            stream.Seek(0, SeekOrigin.Begin);
            return (T)formatter.Deserialize(stream);
        }
    }


    /// <summary>
    /// Perform a deep Copy of an object that is marked with '[DataContract]'
    /// </summary>
    /// <typeparam name="T">The type of object being copied.</typeparam>
    /// <param name="source">The object instance to copy.</param>
    /// <returns>The copied object.</returns>
    public static T CloneUsingDataContracts<T>(T source)
    {
        if (IsDataContract(typeof(T)) == false)
        {
            throw new ArgumentException("The type must be a data contract.", "source");
        }

        // ** Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        DataContractSerializer dcs = new DataContractSerializer(typeof(T));
        using(Stream stream = new MemoryStream())
        {
            using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream))
            {
                dcs.WriteObject(writer, source);
                writer.Flush();
                stream.Seek(0, SeekOrigin.Begin);
                using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader(stream, XmlDictionaryReaderQuotas.Max))
                {
                    return (T)dcs.ReadObject(reader);
                }
            }
        }
    }


    /// <summary>
    /// Helper function to check if a class is a [DataContract]
    /// </summary>
    /// <param name="type">The type of the object to check.</param>
    /// <returns>Boolean flag indicating if the class is a DataContract (true) or not (false) </returns>
    public static bool IsDataContract(Type type)
    {
        object[] attributes = type.GetCustomAttributes(typeof(DataContractAttribute), false);
        return attributes.Length == 1;
    }

} 

4

හරි, මෙම ලිපියේ පරාවර්තනය සමඟ පැහැදිලි උදාහරණ කිහිපයක් ඇත, නමුත් ඔබ එය නිසි ලෙස හැඹිලිගත කිරීමට පටන් ගන්නා තෙක් පරාවර්තනය සාමාන්‍යයෙන් මන්දගාමී වේ.

1000000 වස්තුව ගැඹුරු ක්ලෝන 4,6 කින් (වොචර් විසින් මනිනු ලැබේ) වඩා ඔබ එය නිසි ලෙස හැඹිලිගත කරන්නේ නම්.

static readonly Dictionary<Type, PropertyInfo[]> ProperyList = new Dictionary<Type, PropertyInfo[]>();

ඔබ හැඹිලි ගුණාංග ලබා ගැනීමට හෝ ශබ්ද කෝෂයට අලුතින් එකතු කර ඒවා සරලව භාවිතා කිරීමට වඩා

foreach (var prop in propList)
{
        var value = prop.GetValue(source, null);   
        prop.SetValue(copyInstance, value, null);
}

වෙනත් පිළිතුරකින් මගේ ලිපියේ සම්පූර්ණ කේත පිරික්සුම

https://stackoverflow.com/a/34365709/4711853


2
ඇමතීම prop.GetValue(...)තවමත් පරාවර්තනය වන අතර එය හැඹිලි කළ නොහැක. ප්‍රකාශන ගසක එය සම්පාදනය කළ නමුත් ඉතා වේගවත්
සෙන්ග්

4

මෙම ප්‍රශ්නයට පිළිතුරු සියල්ලම පාහේ සෑහීමකට පත්විය නොහැකි හෝ පැහැදිලිවම මගේ තත්වය තුළ ක්‍රියාත්මක නොවන බැවින්, මම AnyClone රචනා කර ඇති අතර එය මුළුමනින්ම පරාවර්තනයෙන් ක්‍රියාත්මක කර ඇති අතර මෙහි ඇති සියලුම අවශ්‍යතා විසඳා ඇත. සංකීර්ණ ව්‍යුහයක් සහිත සංකීර්ණ වාතාවරණයක වැඩ කිරීමට මට අනුක්‍රමිකකරණය ලබා ගැනීමට නොහැකි වූ අතර IClonableඑය පරමාදර්ශයට වඩා අඩුය - ඇත්ත වශයෙන්ම එය අවශ්‍ය නොවිය යුතුය.

සම්මත නොසලකා හැරීමේ ගුණාංග භාවිතා කරන්නේ [IgnoreDataMember], [NonSerialized]. සංකීර්ණ එකතු කිරීම්, සැකසුම් රහිත දේපල, කියවීමට පමණක් ඇති ක්ෂේත්‍ර ආදිය සඳහා සහාය වේ.

මා කළ ගැටලුවලට මුහුණ දුන් වෙනත් කෙනෙකුට එය උපකාර කරනු ඇතැයි මම බලාපොරොත්තු වෙමි.


4

වියාචනය: මම සඳහන් කළ පැකේජයේ කතුවරයා වෙමි.

2019 දී මෙම ප්‍රශ්නයට ඉහළම පිළිතුරු තවමත් අනුක්‍රමිකකරණය හෝ පරාවර්තනය භාවිතා කරන්නේ කෙසේදැයි මම පුදුමයට පත් වීමි.

අනුක්‍රමිකකරණය සීමා කිරීම (ගුණාංග, විශේෂිත ඉදිකිරීම්කරුවන් ආදිය අවශ්‍ය වේ) සහ එය ඉතා මන්දගාමී වේ

BinaryFormatterසඳහා අවශ්ය Serializable, විශේෂණය JsonConverterවූ parameterless ඉදිකිරීමටත් හෝ ගුණාංග අවශ්ය, හසුරුව වත් ඉතා හොඳින් ක්ෂේත්ර හෝ අතුරු මුහුණත් පමණක් කියවා දෙකම අවශ්ය වඩා 10-30x මන්දගාමී වේ.

ප්‍රකාශන ගස්

ඔබට ඒ වෙනුවට ප්‍රකාශන ගස් හෝ පරාවර්තනය භාවිතා කළ හැකිය. ක්ලෝනකරණ කේතය එක් වරක් පමණක් ජනනය කිරීමට විමසන්න, ඉන්පසු මන්දගාමී පරාවර්තනය හෝ අනුක්‍රමිකකරණය වෙනුවට එම සම්පාදිත කේතය භාවිතා කරන්න.

ගැටලුව මා විසින්ම සොයාගෙන ඇති අතර සතුටුදායක විසඳුමක් නොමැති නිසා, සෑම වර්ගයකටම ගැලපෙන පරිදි සකස් කරන ලද පැකේජයක් නිර්මාණය කිරීමට මම තීරණය කළෙමි .

ඔබට ව්‍යාපෘතිය GitHub වෙතින් සොයාගත හැකිය: https://github.com/marcelltoth/ObjectCloner

භාවිතය

ඔබට එය NuGet වෙතින් ස්ථාපනය කළ හැකිය. එක්කෝ ObjectClonerපැකේජය ලබා ගෙන එය භාවිතා කරන්න:

var clone = ObjectCloner.DeepClone(original);

හෝ ඔබේ වස්තු වර්ගය දිගුවන් සමඟ දූෂණය කිරීමට ඔබට අවශ්‍ය නැතිනම් එය ObjectCloner.Extensionsලියන්න:

var clone = original.DeepClone();

කාර්ය සාධනය

පංති ධූරාවලියක් ක්ලෝන කිරීමේ සරල මිණුම් දණ්ඩක් මඟින් පරාවර්තනය භාවිතා කිරීමට වඩා ~ 3x වේගවත්, නිව්ටන්සොෆ්ට් වලට වඩා x 12x වේගවත් බව පෙන්වයි BinaryFormatter.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.