【问题标题】:Is is possible to set value in property without a setter?是否可以在没有设置器的情况下在属性中设置值?
【发布时间】:2019-06-16 16:01:31
【问题描述】:

我正在使用这个包 (https://github.com/shawnmclean/Mandrill-dotnet) 在 .net 应用程序中实现 mandrill 现在有一个模型“EmailMessage”用于发送电子邮件。 EmailMessage 模型内部有一个属性“GlobalMergeVars”:

   [JsonProperty("global_merge_vars")]
   public List<MergeVar> GlobalMergeVars { get; }

现在我们可以看到 GlobalMergeVars 没有设置器,但我必须为此设置一个值。如果我们转到此链接 (https://mandrillapp.com/api/docs/messages.html) 并单击“试用”按钮,那么我们可以为 GlobalMergeVars 设置值,但我认为我正在使用的包中存在一些问题。但我不能切换到其他包,因为它与其他包相比非常灵活。那么无论如何要为 GlobalMergeVars 设置值吗?

PS:我还在 github repo 上打开了一个问题。但由于截止日期临近,我需要快速修复。

【问题讨论】:

  • 从类的构造函数中试过了吗?
  • EmailMessage 类中只有一个空的构造函数
  • 请添加更多详细代码!还要告诉你要在哪种情况下设置值。
  • 答案是:从第 376 行开始阅读github.com/shawnmclean/Mandrill-dotnet/blob/master/src/Mandrill/…。该方法专为您的情况设计
  • 谢谢,这正是我想要的。

标签: c# .net asp.net-core-2.0 mailchimp mandrill


【解决方案1】:

我想我找到了你所说的课程here。尽管EmailMessage 的属性与您在问题中显示的不同:

public class EmailMessage
{
    #region Public Properties
    ...
    /// <summary>
    ///   Gets the global_merge_vars.
    /// </summary>
    public List<MergeVar> GlobalMergeVars { get; private set; }

(此处的代码与问题中给出的代码之间的差异无关紧要 - 我只是想知道我是否正在查看正确的文件!)

缺少的set 相当于private set。该类中有以下方法,可让您设置变量:

public void AddGlobalVariable(string name, dynamic content)
{
  if (GlobalMergeVars == null)
  {
    GlobalMergeVars = new List<MergeVar>();
  }

  var mv = new MergeVar {Name = name, Content = content};
  GlobalMergeVars.Add(mv);
}

【讨论】:

    【解决方案2】:

    我知道您已经得到了针对您的特定情况的答案,但是由于问题是“是否可以在没有 setter 的情况下在属性中设置值?”并且明确地说您不能直接从类外设置值,我只是想提供一个这样做的例子......

    如果您愿意使用反射,您实际上可以从类外部设置值。

    你只需要有点棘手。

    您需要滥用这样一个事实,即为 Auto 属性生成的私有字段是由编译器脱糖而不是由 JITer 生成的。

    这意味着程序集中实际上会有一个这样命名的私有字段:k__BackingField.

    编译器去糖添加 因为它们被开发人员代码添加为私有字段名称是非法的。

    这是一个示例,我试图查找名为 GlobalIgnores 的属性的私有支持字段,该属性没有设置器(与拥有私有设置器的含义相同)。

    public class Configuration
    {
        public Configuration()
        {
            GlobalIgnores = new List<string>{"IgnoredPropertyName"};
        }
        
        public IEnumerable<string> GlobalIgnores { get; }
    }
    
    protected IList<string> PropertyNamesToTempIgnore { get; } = new List<string>{"ReplacedIgnoredPropertyName"};
    
    public void SetPrivateBackingFieldOfPropertyWithNoSetter()
    {
        var configuration = new Configuration();
        var configurationType = configuration.GetType();
        const string globalIgnoresFieldName = "<GlobalIgnores>k__BackingField";
        var fieldInfo = configurationType.GetField(globalIgnoresFieldName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
        fieldInfo.SetValue(configuration, PropertyNamesToTempIgnore);
    }
    

    免责声明:除非绝对必要,否则我不建议使用它,因为这些自动生成的私有字段的命名不是 100% 在 C# 规范中指定的,并且它可能会在不同的编译器实现中发生变化。

    【讨论】:

      【解决方案3】:

      很抱歉成为坏消息的承担者,但如果没有公共设置器,您无法直接从类外设置值。其他选项将通过构造函数或允许这样的方法。但您似乎没有任何可用的此类选项。

      附带说明一下,只需检查该属性是否可能没有您可以作为一个整体设置的父属性。例如在 C# 中使用字体时,例如设置标签的字体。某些 Font 对象的属性是“只读的”,不能在外部设置。但是可以设置 Font 对象本身。因此,在这种情况下,您必须在本地创建一个新的 Font 对象并设置所需的道具,然后将其分配/设置为新的 Font。

      希望您能及时找到解决办法。

      更新:

      Rufo 爵士刚刚给了你解决方案:

      答案是:阅读时间 github.com/shawnmclean/Mandrill-dotnet/blob/master/src/Mandrill/… 从第 376 行开始。该方法专为您的情况设计

      【讨论】:

      • 你忘了说可能有一种方法可以完成这项工作(事实上,有一个);o)
      • @SirRufo - 不,我确实提到过,只是添加了您的解决方案。赞一个!
      猜你喜欢
      • 2014-01-07
      • 1970-01-01
      • 1970-01-01
      • 2011-05-01
      • 2018-01-03
      • 2011-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多