【问题标题】:Force C# Compiler to Create an Unused Object Instance强制 C# 编译器创建未使用的对象实例
【发布时间】:2010-06-02 22:57:13
【问题描述】:

是的,这正是我想要做的 :) 至少对于特定的课程。 问题是,我创建了一个对象的静态实例,但我不直接使用它。由于我在构造函数中进行了一些操作,例如将对象添加到列表中,因此在获取列表之前必须至少调用一次构造函数。

我猜编译器只是优化了未使用的对象。

必须有一个简单的解决方案:-/

编辑

好吧,我可能错过了一些东西。让我发布我的代码。我为自定义枚举编写了一个类。

        public class TypeSafeEnum<TNameType, TValueType>
        {
        protected readonly TNameType name;
        protected readonly TValueType value;

        private static List<TypeSafeEnum<TNameType, TValueType>> listEnums = new List<TypeSafeEnum<TNameType, TValueType>>();

        protected TypeSafeEnum(TNameType name, TValueType value)
        {
          this.name = name;
          this.value = value;

          listEnums.Add(this);
        }

        public TNameType Name
        {
          get { return name; }
        }

        public TValueType Value
        {
          get { return value; }
        }

        public static TypeSafeEnum<TNameType, TValueType> GetName(TNameType name)
        {
          TypeSafeEnum<TNameType, TValueType> tse = null;
          for (int i = 0; i < listEnums.Count; i++)
          {
            TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i];
            if (EqualityComparer<TNameType>.Default.Equals(typeSafeEnum.name, name))
            {
              tse = typeSafeEnum;            
            }
          }
          return tse;
        }

        public static TypeSafeEnum<TNameType, TValueType> GetValue(TValueType value)
        {
          TypeSafeEnum<TNameType, TValueType> tse = null;
          for (int i = 0; i < listEnums.Count; i++)
          {
            TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i];
            if (EqualityComparer<TValueType>.Default.Equals(typeSafeEnum.value, value))
            {
              tse = typeSafeEnum;
            }
          }
          return tse;
        }

        public static TNameType[] GetNames()
        {
          TNameType[] names = new TNameType[listEnums.Count];
          for (int i = 0; i < listEnums.Count; i++)
          {
            TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i];
            names[i] = typeSafeEnum.name;
          }
          return names;
        }

        public static TValueType[] GetValues()
        {
          TValueType[] values = new TValueType[listEnums.Count];
          for (int i = 0; i < listEnums.Count; i++)
          {
            TypeSafeEnum<TNameType, TValueType> typeSafeEnum = listEnums[i];
            values[i] = typeSafeEnum.value;
          }
          return values;
        }
        }


        public abstract class StringEnum : TypeSafeEnum<string, int>
        {
            protected StringEnum(string name, int value) : base(name, value)
            {
            }
        }


        public sealed class FileOptionEnum : StringEnum
        {
            public static readonly FileOptionEnum Name = new FileOptionEnum("Name", 0);
            public static readonly FileOptionEnum Extension = new FileOptionEnum("Extension", 1);
            public static readonly FileOptionEnum Size = new FileOptionEnum("Size", 2);
            public static readonly FileOptionEnum LastModified = new FileOptionEnum("Last Modified", 3);
            public static readonly FileOptionEnum LastOpened = new FileOptionEnum("Last Opened", 4);
            public static readonly FileOptionEnum Created = new FileOptionEnum("Created", 5);

            public FileOptionEnum(string name, int value) : base(name, value)
            {
            }
        }

这是我的使用方法:

        // if I omit this line it returns me empty array
        FileOptionEnum @enum = FileOptionEnum.Name;
        string[] names = FileOptionEnum.GetNames();
        cbFileOptions.Items.AddRange(names);

【问题讨论】:

  • 也许你可以讨论你想要达到的目标;可能有替代解决方案?
  • “静态实例”不存在。我想你的意思是你有一个通过创建类的实例来初始化的静态变量?

标签: c# compiler-construction instance jit


【解决方案1】:

你可以简单地写

new YourObject();

这不会被优化掉。
但是,除非类的构造函数将自身保存在某个地方(例如,将对象添加到列表或静态字段,或者将事件处理程序添加到其他内容),否则该对象可能会立即被垃圾回收。

【讨论】:

    【解决方案2】:

    首先,请确认编译器确实优化了代码。很有可能,它真的没有:如果你的构造函数调用有副作用,编译器实际上没有权利摆脱它。

    如果它确实被优化掉了,你可以使用GC.KeepAlive 方法来保证对象仍然存在:

    GC.KeepAlive( new MyObj() );
    

    这个方法实际上并没有做任何事情——它的主体是空的。但它的特殊之处在于它无法优化。所以如果你用一些参数调用它,那么那个参数也不能被优化出来。

    【讨论】:

    • @SLaks:为什么会泄漏内存?使用 keep-alive 语句似乎很愚蠢。当调用实际上向 GC 发出信号表明可以回收新创建的对象时,为什么还要尝试保持新对象处于活动状态。这就是它会“泄漏内存”的原因吗?
    • 因为对象将永远被收集。根据对象是什么以及它的作用,这可能是也可能不是问题。
    • 很抱歉听起来很执着,但试图理解。我从来不需要使用keep-alive。为什么永远不会被收集?备注部分指出,“KeepAlive 方法不执行任何操作,并且除了延长作为参数传入的对象的生命周期之外不会产生任何副作用。”所以传递一个新对象什么都不做。这会愚弄 GC 来让对象永远活着吗?
    • @Slaks - KeepAlive 仅充当不透明的方法。一旦超出它,它什么也不做。我认为在这种情况下KeepAlive 什么都不做KeepAlive 的典型用法是当您在一个方法顶部初始化一个 var(例如 Mutex)时,您再也不会接触,但您真的不想这样做被垃圾收集,直到方法退出。 KeepAlive 算作对变量的读取,因此必须保留该值。否则,来自未读取堆栈位置的变量的引用可能有资格被收集。
    • 我误解了KeepAlive;我收回我的评论。谢谢你启发我。
    【解决方案3】:

    你的想法行不通。

    静态List&lt;TypeSafeEnum&lt;TNameType, TValueType&gt;&gt; listEnums 字段将由具有相同名称和值类型的所有TypeSafeEnum 类共享。

    要解决这个问题,为实际的枚举类添加一个参数,如下所示:

    public class TypeSafeEnum<TEnum, TName, TValue> where TEnum : TypeSafeEnum<TEnum, TName, TValue>
    

    (然后您可以将所有TypeSafeEnum&lt;...&gt; 字段和参数替换为TEnum

    我很确定这也将解决您的实际问题。
    由于基础TypeSafeEnum 类现在引用继承的枚举类,继承类的静态构造函数将运行,初始化值。

    【讨论】:

    • 我明白了。谢谢。那你有什么建议呢?
    • OK 列表现在工作正常,但实际问题仍然存在。 :( 如果 FileOptionEnum.Name 没有手动调用,FileOptionEnum.GetNames() 仍然给出一个空列表。
    • 您可以在基类的静态构造函数中使用反射。
    【解决方案4】:

    如果您只是使用一些静态功能,为什么要使用实例呢?创建一个静态类,并拥有一个静态的“Initialize()”方法,您可以调用该方法来设置您的对象。

    【讨论】:

      【解决方案5】:

      在您尝试显式访问静态成员之前,不能保证它们会被初始化。您可以通过创建显式静态构造函数(以避免 beforeFieldInit 行为)并显式访问静态方法(如虚拟 Init 方法)来强制静态初始化来解决此问题。

      【讨论】:

        猜你喜欢
        • 2023-03-24
        • 1970-01-01
        • 1970-01-01
        • 2021-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-25
        相关资源
        最近更新 更多