是否可以在没有 setter 的情况下在 属性 中设置值?
Is is possible to set value in property without a setter?
我正在使用此包在 .net 应用程序中实现 mandrill (https://github.com/shawnmclean/Mandrill-dotnet) 现在有一个模型 "EmailMessage" 用于发送电子邮件。在 EmailMessage 模型内部有一个 属性 "GlobalMergeVars":
[JsonProperty("global_merge_vars")]
public List<MergeVar> GlobalMergeVars { get; }
现在我们可以看到 GlobalMergeVars 没有 setter,但我必须为此设置一个值。如果我们转到 link (https://mandrillapp.com/api/docs/messages.html) 并单击 "Try it" 按钮,那么我们可以为 GlobalMergeVars 设置值,但我认为我使用的包存在一些问题。但是我不能切换到其他包,因为与其他包相比它非常灵活。那么有没有办法为 GlobalMergeVars 设置值?
PS:我还在 github 回购上打开了一个问题。但由于截止日期很近,我需要快速修复。
很抱歉成为坏消息的传递者,但是如果没有 public setter,则不能直接从 class 外部设置值。其他选项将通过构造函数或允许这样的方法。但是您似乎没有任何可用的选项。
附带说明一下,只需检查一下 属性 是否可能没有可以作为一个整体设置的父 属性。例如在 C# 中使用字体时,例如设置标签的字体。 Font 对象的一些属性是 "read-only" 并且不能在外部设置。但是可以设置 Font 对象本身。因此,在这种情况下,您必须在本地创建一个新的 Font 对象并设置所需的道具,然后 assign/set 作为新的 Font。
希望您能及时找到解决方法。
更新:
Rufo 先生刚刚给了你解决方案:
The answer is: read at
github.com/shawnmclean/Mandrill-dotnet/blob/master/src/Mandrill/…
starting from line 376. That method is designed for your case
我想我找到了您所说的 class 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
。 class 中有以下方法,可让您设置变量:
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);
}
我知道您已经为您的特定案例找到了答案,但由于问题是“是否可以在没有 setter 的情况下在 属性 中设置值?" 并且明确地说你不能直接从 class 之外设置值,我只是想提供一个这样做的例子......
如果您愿意使用反射,您实际上可以从 class 外部设置值。
你只是需要有点技巧。
您需要滥用这样一个事实,即为 Auto 属性创建的私有字段是由编译器脱糖而不是由 JITer 创建的。
这意味着在程序集中实际上会有一个这样命名的私有字段:<[NameOfProperty]>k__BackingField.
编译器脱糖添加了 < 和 >,因为开发人员代码将它们添加为私有字段名称是非法的。
这是一个示例,其中我试图找到名为 GlobalIgnores 的 属性 的私有支持字段,它没有 setter(意思与拥有私有 setter).
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# 规范中指定,并且它可能会在不同的编译器实现中发生变化。
我正在使用此包在 .net 应用程序中实现 mandrill (https://github.com/shawnmclean/Mandrill-dotnet) 现在有一个模型 "EmailMessage" 用于发送电子邮件。在 EmailMessage 模型内部有一个 属性 "GlobalMergeVars":
[JsonProperty("global_merge_vars")]
public List<MergeVar> GlobalMergeVars { get; }
现在我们可以看到 GlobalMergeVars 没有 setter,但我必须为此设置一个值。如果我们转到 link (https://mandrillapp.com/api/docs/messages.html) 并单击 "Try it" 按钮,那么我们可以为 GlobalMergeVars 设置值,但我认为我使用的包存在一些问题。但是我不能切换到其他包,因为与其他包相比它非常灵活。那么有没有办法为 GlobalMergeVars 设置值?
PS:我还在 github 回购上打开了一个问题。但由于截止日期很近,我需要快速修复。
很抱歉成为坏消息的传递者,但是如果没有 public setter,则不能直接从 class 外部设置值。其他选项将通过构造函数或允许这样的方法。但是您似乎没有任何可用的选项。
附带说明一下,只需检查一下 属性 是否可能没有可以作为一个整体设置的父 属性。例如在 C# 中使用字体时,例如设置标签的字体。 Font 对象的一些属性是 "read-only" 并且不能在外部设置。但是可以设置 Font 对象本身。因此,在这种情况下,您必须在本地创建一个新的 Font 对象并设置所需的道具,然后 assign/set 作为新的 Font。
希望您能及时找到解决方法。
更新:
Rufo 先生刚刚给了你解决方案:
The answer is: read at github.com/shawnmclean/Mandrill-dotnet/blob/master/src/Mandrill/… starting from line 376. That method is designed for your case
我想我找到了您所说的 class 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
。 class 中有以下方法,可让您设置变量:
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);
}
我知道您已经为您的特定案例找到了答案,但由于问题是“是否可以在没有 setter 的情况下在 属性 中设置值?" 并且明确地说你不能直接从 class 之外设置值,我只是想提供一个这样做的例子......
如果您愿意使用反射,您实际上可以从 class 外部设置值。
你只是需要有点技巧。
您需要滥用这样一个事实,即为 Auto 属性创建的私有字段是由编译器脱糖而不是由 JITer 创建的。
这意味着在程序集中实际上会有一个这样命名的私有字段:<[NameOfProperty]>k__BackingField.
编译器脱糖添加了 < 和 >,因为开发人员代码将它们添加为私有字段名称是非法的。
这是一个示例,其中我试图找到名为 GlobalIgnores 的 属性 的私有支持字段,它没有 setter(意思与拥有私有 setter).
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# 规范中指定,并且它可能会在不同的编译器实现中发生变化。