Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在字段中存储所有ctor参数_C#_Oop - Fatal编程技术网

C# 如何在字段中存储所有ctor参数

C# 如何在字段中存储所有ctor参数,c#,oop,C#,Oop,我正在学习C#,在编写代码时想到了一个想法。是否可以以简单的方式自动将参数从构造函数存储到字段,而无需在每个变量上写入this.var=var 例如: class MyClass { int var1; int var2; int var3; int var4; public MyClass(int var1, int var2, int var3, int var4){ this.var1 = var1; this.var

我正在学习C#,在编写代码时想到了一个想法。是否可以以简单的方式自动将参数从构造函数存储到字段,而无需在每个变量上写入
this.var=var

例如:

class MyClass
{
    int var1;
    int var2;
    int var3;
    int var4;
    public MyClass(int var1, int var2, int var3, int var4){
        this.var1 = var1;
        this.var2 = var2;
        this.var3 = var3;
        this.var4 = var4;
    }
}

如果名称相同,是否有办法避免写入this.varX=varX,并将所有变量保存到字段中?

问题的答案是否定的,但您可以使用属性获得类似的修复:

class MyClass
{
    public int Var1 {get;set;}
    public int Var2 {get;set;}
    public int Var3 {get;set;}
    public int Var4 {get;set;}
    public MyClass(){

    }
}

void Main()
{
   var myClass = new MyClass
   {
     Var1 = 1,
     Var2 = 2,
     Var3 = 3,
   };
}

如果首先定义变量,可以使用visual Studio的“快速操作”工具为您生成构造函数;这使您可以选择要包括的当前定义的类字段

使用它将插入一个构造函数类,其中包含所有选定字段作为参数,并将值分配给字段


这不会减少代码量,但会减少所需的键入量。

不,在当前版本的C#中,没有比这更简单的方法。为了解决这个问题,C#6.0预发行版中有一个称为主构造函数的新特性,但它在最终发行版之前就被删除了


目前,我相信C团队正在致力于向语言中添加记录:-这将使使用简单的数据类变得更简单,就像在F#

中一样,用简单的术语来说,这是你做不到的。使用它是没有必要的,但是它很优雅,并且显示了加强变量是类上下文的一部分这一事实的意图

但是,这里的问题是由于参数和实例变量的名称相同

编译器无法区分同名变量(可能是循环引用)

使用
this
关键字可以告诉编译器我们引用的是该变量的当前实例

我认为您可以通过更好的变量命名方法来改进代码和编码本身

例如
var1 var2 var3
他们什么都没说,让代码很难理解

尽量具体、详细:
例如名、姓、地址等。它们是不言自明的。

短:不,长:是的,有一个黑客

可以混合使用反射和将参数存储在临时数组中来实现这一点

class TestClass
{
    public string var1 { get; set; }
    public string var2 { get; set; }
    public string var3 { get; set; }

    public TestClass(string var1, string var2, string var3) : base()
    {
        var param = new { var1, var2, var3 };
        PropertyInfo[] info = this.GetType().GetProperties();

        foreach (PropertyInfo infos in info) {
            foreach (PropertyInfo paramInfo in param.GetType().GetProperties()) {
                if (infos.Name == paramInfo.Name) {
                    infos.SetValue(this, paramInfo.GetValue(param, null));
                }
            }
        }

    }

}

这基本上是循环遍历属性,检查名称是否等于存储在临时数组中的参数名称(无法通过反射获取参数值),并在匹配时赋值


注意:我不建议这样分配属性,但为了证明这是可能的,我提出了这个方法。

除了直接分配属性外,我可以想出一种在构造函数中填充对象字段的不容易的方法。正如其他人所说,可能有一些使用反射的变通方法,但它甚至不接近手动填充字段的简单性

从构造函数中填充类字段而不向构造函数添加任何实际代码的一种方法可能是在构建后更改IL,并添加您自己手动添加的代码。对于库或NuGet包来说,这可能是一种有趣的方法


除此之外,我没有看到从构造函数填充类的字段而不直接赋值的用例。如果您只有几个必填字段,那么构造函数实现起来非常简单,因此不值得这么做。如果您有一个包含大量参数的大型构造函数,那么这看起来像是一种代码味道。您可以使用非常直接的模式。

不,主要是因为这种模式非常僵硬。例如,如果您想要一个不会设置为字段的参数,该怎么办;这句话的语法是什么?您可能提出的大多数解决方案要么是约束性的,要么与当前方法一样冗长

不过,这种僵化只是一般情况下的一个问题。如果这个模式适合您,那么您可以通过继承来定义它,继承是这个工作的正确工具

因此,您可以定义一组通用的
Tuple
-类,这些类可以从中继承:

public abstract class TupleBase<T1>
{
    public T1 Argument1 { get; private set; }

    public TupleBase(T1 argument1)
    {
       this.Argument1 = argument1;
    }
}

public abstract class TupleBase<T1, T2>
{
    public T1 Argument1 { get; private set; }
    public T2 Argument2 { get; private set; }

    public TupleBase(T1 argument1, T2 argument2)
    {
       this.Argument1 = argument1;
       this.Argument2 = argument2;
    }
}

public abstract class TupleBase<T1, T2, T3>
{
    public T1 Argument1 { get; private set; }
    public T2 Argument2 { get; private set; }
    public T3 Argument3 { get; private set; }

    public TupleBase(T1 argument1, T2 argument2, T3 argument3)
    {
       this.Argument1 = argument1;
       this.Argument2 = argument2;
       this.Argument3 = argument3;
    }
}

//  Etc..
变成

class MyClass : TupleBase<int, int, int, int>
{
    public MyClass(int var1, int var2, int var3, int var4)
        :   base(var1, var2, var3, var4)
    {
    }
}
,其中,
.SetConstructorValues()
是一种通用扩展方法

private static System.Collections.ConcurrentDictionary<Type, Action<object, object[]>> ConstructorSetterDictionary { get; private set; }

public static void SetConstructorValues<T_SetClass>(
            this T_SetClass instanceToSetValuesFor
        ,   params object[] constructorArguments
    )
{
    var instanceType = typeof(T_SetClass);

    Action<object, object[]> constructorSetterAction;
    if (!ConstructorSetterDictionary.TryGetValue(
                instanceType
            ,   out constructorSetterAction
        ))
    {
        throw new Exception("Populate the dictionary!  Also change this Exception message; it's from a StackOverflow example and not really designed to actually be written like this.");
    }

    constructorSetterAction(
                instanceToSetValuesFor
            ,   constructorArguments
        );
}
private static System.Collections.ConcurrentDictionary构造函数setterDictionary{get;private set;}
公共静态void SetConstructorValues(
此T_SetClass InstanceToSetValue用于
,参数对象[]构造函数参数
)
{
var instanceType=typeof(T_SetClass);
动作构造器动作;
if(!ConstructorSetterDictionary.TryGetValue)(
实例类型
,out构造函数引用
))
{
抛出新异常(“填充字典!同时更改此异常消息;它来自StackOverflow示例,并不是真正设计为这样编写的。”);
}
构造器吸引子(
InstanceToSetValues for
,构造函数参数
);
}
,其中,
ConstructorSetterDictionary
是每个
类型
的setter-
操作
的字典,根据您喜欢的逻辑推断(例如,将带有参数名的构造函数与字段匹配),在程序启动时使用反射填充

从概念上讲,基于对象的
类型获得这样的方法基本上就是虚拟方法的工作方式,其中
构造函数setterdictionary
是一个虚拟查找表

我发现这种元编程在我自己的工作中很有用,但请注意,在某些时候,它不再是C#。

您可以使用tuple“magic”


据我所知,不(不可以。但是字段和参数应该有相似但不同的名称——例如,字段总是以下划线开头是f
class MyClass
{
    int var1;
    int var2;
    int var3;
    int var4;

    public MyClass(int var1, int var2, int var3, int var4){
        this.SetConstructorValues(var1, var2, var3, var4);
    }
}
private static System.Collections.ConcurrentDictionary<Type, Action<object, object[]>> ConstructorSetterDictionary { get; private set; }

public static void SetConstructorValues<T_SetClass>(
            this T_SetClass instanceToSetValuesFor
        ,   params object[] constructorArguments
    )
{
    var instanceType = typeof(T_SetClass);

    Action<object, object[]> constructorSetterAction;
    if (!ConstructorSetterDictionary.TryGetValue(
                instanceType
            ,   out constructorSetterAction
        ))
    {
        throw new Exception("Populate the dictionary!  Also change this Exception message; it's from a StackOverflow example and not really designed to actually be written like this.");
    }

    constructorSetterAction(
                instanceToSetValuesFor
            ,   constructorArguments
        );
}
    class MyClass
    {
        int var1;
        int var2;
        int var3;
        int var4;
        public MyClass(int var1, int var2, int var3, int var4) => (this.var1, this.var2, this.var3, this.var4) = (var1, var2, var3, var4);
    }