Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by jimjames · Feb 17, 2016 at 09:02 PM · generic list

Copy one Generic List to another one

Weird question. I would like to copy a generic list from script A to another generic list from script B, but I would like to do this in another script "C"? Any thoughts? I cant seem to get anything working in Script C.

Both generic list have the same variable inside the public class, and variable range from strings, ints, floats, gameobjects, and transforms. I am thinking of doing it manually for each variable inside the generic lists, but I am trying to see if there is a faster way of doing it?

Thanks: James

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by Cherno · Feb 17, 2016 at 09:22 PM

If you just want to have both scripts referencing the same list, you can simple use

 scriptB.list = scriptA.list;

However, if you want to actually copy the list, I'd use his handy helper class I found online:

 using System;
 using System.Reflection;//for copying objects
 using System.Linq;//for string[].Contains()
 using UnityEngine;//for print
 
 public class CopyData {
     
     /// <summary>
     /// Copies the data of one object to another. The target object gets properties of the first. 
     /// Any matching properties (by name) are written to the target.
     /// </summary>
     /// <param name="source">The source object to copy from</param>
     /// <param name="target">The target object to copy to</param>
     public static void CopyObjectData(object source, object target)
     {
         CopyObjectData(source, target, String.Empty, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
     }
     
     /// <summary>
     /// Copies the data of one object to another. The target object gets properties of the first. 
     /// Any matching properties (by name) are written to the target.
     /// </summary>
     /// <param name="source">The source object to copy from</param>
     /// <param name="target">The target object to copy to</param>
     /// <param name="excludedProperties">A comma delimited list of properties that should not be copied</param>
     /// <param name="memberAccess">Reflection binding access</param>
     public static void CopyObjectData(object source, object target, string excludedProperties, BindingFlags memberAccess)
     {
         string[] excluded = null;
         if (!string.IsNullOrEmpty(excludedProperties))
         {
             excluded = excludedProperties.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
         }
         
         MemberInfo[] miT = target.GetType().GetMembers(memberAccess);
 
         foreach (MemberInfo Field in miT)
         {
             string name = Field.Name;
             
             // Skip over excluded properties
             if (string.IsNullOrEmpty(excludedProperties) == false
                 && excluded.Contains(name))
             {
                 continue;
             }
             
             
             if (Field.MemberType == MemberTypes.Field)
             {
                 FieldInfo sourcefield = source.GetType().GetField(name);
                 if (sourcefield == null) { continue; }
                 
                 object SourceValue = sourcefield.GetValue(source);
                 ((FieldInfo)Field).SetValue(target, SourceValue);
             }
 
             else if (Field.MemberType == MemberTypes.Property)
             {
                 PropertyInfo piTarget = Field as PropertyInfo;
                 PropertyInfo sourceField = source.GetType().GetProperty(name, memberAccess);
                 if (sourceField == null) { continue; }
                 
                 if (piTarget.CanWrite && sourceField.CanRead)
                 {
                     object targetValue = piTarget.GetValue(target, null);
                     object sourceValue = sourceField.GetValue(source, null);
                     
                     if (sourceValue == null) { continue; }
                     
                     if (sourceField.PropertyType.IsArray
                         && piTarget.PropertyType.IsArray
                         && sourceValue != null ) 
                     {
                         CopyArray(source, target, memberAccess, piTarget, sourceField, sourceValue);
                     }
                     else
                     {
                         CopySingleData(source, target, memberAccess, piTarget, sourceField, targetValue, sourceValue);
                     }
                 }
             }
 
         }
     }
     
     private static void CopySingleData(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object targetValue, object sourceValue)
     {
         //instantiate target if needed
         if (targetValue == null
             && piTarget.PropertyType.IsValueType == false
             && piTarget.PropertyType != typeof(string))
         {
             if (piTarget.PropertyType.IsArray)
             {
                 targetValue = Activator.CreateInstance(piTarget.PropertyType.GetElementType());
             }
             else
             {
                 targetValue = Activator.CreateInstance(piTarget.PropertyType);
             }
         }
         
         if (piTarget.PropertyType.IsValueType == false
             && piTarget.PropertyType != typeof(string))
         {
             CopyObjectData(sourceValue, targetValue, "", memberAccess);
             piTarget.SetValue(target, targetValue, null);
         }
         else
         {
             if (piTarget.PropertyType.FullName == sourceField.PropertyType.FullName)
             {
                 object tempSourceValue = sourceField.GetValue(source, null);
                 piTarget.SetValue(target, tempSourceValue, null);
             }
             else
             {
                 CopyObjectData(piTarget, target, "", memberAccess);
             }
         }
     }
     
     private static void CopyArray(object source, object target, BindingFlags memberAccess, PropertyInfo piTarget, PropertyInfo sourceField, object sourceValue)
     {
         int sourceLength = (int)sourceValue.GetType().InvokeMember("Length", BindingFlags.GetProperty, null, sourceValue, null);
         Array targetArray = Array.CreateInstance(piTarget.PropertyType.GetElementType(), sourceLength);
         Array array = (Array)sourceField.GetValue(source, null);
         
         for (int i = 0; i < array.Length; i++)
         {
             object o = array.GetValue(i);
             object tempTarget = Activator.CreateInstance(piTarget.PropertyType.GetElementType());
             CopyObjectData(o, tempTarget, "", memberAccess);
             targetArray.SetValue(tempTarget, i);
         }
         piTarget.SetValue(target, targetArray, null);
     }
 }

It can be used for virtually anything that needs to be coöied (as opposed to jsut a reference). It doesn't matter if it's a single variable, collection, or a whole script/class instance.

For you case, you would then use

 CopyData.CopyObjectData(scriptA.list, scriptB.list);

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image jimjames · Feb 17, 2016 at 09:40 PM 0
Share

I dont even know where to begin. I was trying to find a simple way of doing it, like listA = listB. I think ill just transfer the values manually. Thanks for your time tho.

avatar image HatrickOreally · Jan 12, 2021 at 12:35 AM 0
Share

I have been bashing my head against a wall for the last 10 hours trying to find a concise way to do this.

You are a life saver!

avatar image Bunny83 · Jan 12, 2021 at 05:00 AM 0
Share

Please do not ever use this method on a generic List. This method does not perform a deep copy but a shallow copy. That means it literally just copies the values of the direct members of the provided object to the destination object. Doing this on a generic List you will create a zombie twin List. That means both of your list instances will use the same internal array after that copy.

Interestingly the method does properly create a new array if it encounters a property of an array type. However fields are not treated this way. Since the default binding flags do include nonpublic members as well the result is not than dangerous.

avatar image
1

Answer by Bunny83 · Jan 12, 2021 at 05:12 AM

If you want to copy a list from one script to another there are generally 3 different ways.


First of all if you are happy that both scripts will actually use the same list, you can simply assign the list of script1 to the list varable of script2. That way both scripts will be using the same List instance. So if script1 adds an element to the list, script2 will see that element as well.


The other two ways are about actually copying the content of the list. The first usual way is to simply create a new list and provide the source list from the other script as parameter to the constructor. This will copy the content of the source list into the newly created list.


If you want to do this copying more frequence and you want to avoid creating a new list all the time (to prevent garbage generation), the general approach is to first call Clear() on the target list to make it empty and then use AddRange and provide the source list.


To follow the code example of Cherno, here are the 3 solutions:

 // both scripts will use the list of scriptA after that line
 scriptB.list = scriptA.list;
 
 // we just create a new list and fill it with the same content of the other one
 scriptB.list = new List<YourElementType>(scriptA.list);
 
 // This is the garbage friendly version
 scriptB.list.Clear();
 scriptB.list.AddRange(scriptA.list);
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

36 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Iterate through Generic List 2 Answers

see C# 2D Generic List in inspector 1 Answer

Generic Lists, Item adding and removing options 1 Answer

How to add class to a static Generic List 1 Answer

Loading game objects into a generic list in specified order 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges