【问题标题】:Passing static parameters to a class将静态参数传递给类
【发布时间】:2011-02-15 13:23:15
【问题描述】:

据我所知,您不能将参数传递给 C# 中的静态构造函数。 但是,在创建类的实例之前,我确实需要传递 2 个参数并将它们分配给静态字段。我该怎么办?

【问题讨论】:

  • 如果你能定义“静态参数”会有所帮助——这不是我熟悉的术语......
  • @Jon:我假设他们想将参数传递给静态构造函数。当然,这不起作用,但我看到它是为了让他们想用运行时传入的数据静态初始化类的静态字段。
  • @Johannes:让我感到困惑的是 OP 希望从哪里传递它们来自。与实例构造函数不同,静态构造函数不会被“调用”——它们只是在适当的时间执行。我希望如果 OP 澄清他们真正想要实现的目标,答案可能会变得更加清晰。
  • 我已经编辑了我的答案。希望现在更容易理解。
  • 请提供更多ovaltine代码!

标签: c# static-members static-constructor


【解决方案1】:

我假设您的意思是类的静态成员?在这种情况下,您可以这样做:

public class MyClass
{
    public static int MyInt = 12;
    public static MyOtherClass MyOther = new MyOtherClass();    
}

保证在实例化任何类之前实例化这些静态成员。

如果您需要复杂的逻辑,请在静态构造函数中进行:

public class MyClass
{
    public static int MyInt;
    public static MyOtherClass MyOther;
    static MyClass()
    {
        MyInt = 12;
        MyOther = new MyOtherClass();
    }
}

编辑

根据您的编辑,我想说在实例化类之前将值分配给它们需要的值,如下所示:

public class MyClass
{
    public static int MyInt;
    public static MyOtherClass MyOther;
}

// elsewhere in code, before you instantiate MyClass:
MyClass.MyInt = 12;
MyClass.MyOther = new MyOtherClass();
MyClass myClass = new MyClass();

也就是说,这个方法不能保证 MyInt 和 MyOther 在 MyClass 被实例化之前被设置。它会起作用,但在实例化 MyClass 之前需要遵守纪律。

您可能遵循的另一种模式如下所示:

public class MyClass
{
    private static int MyInt;
    private static MyOtherClass MyOther;
    private static bool IsStaticInitialized = false;

    public static InitializeStatic(int myInt, MyOtherClass other)
    {
        MyInt = myInt;
        MyOther = other;
        IsStaticInitialized = true;
    }

    public MyClass()
    {
        if(!IsStaticInitialized)
        {
            throw new InvalidOperationException("Static Not Initialized");
        }
        // other constructor logic here. 
    }
}

// elsewhere in your code:
MyClass.InitializeStatic(12, new MyOtherClass());
MyClass myClass = new MyClass();

// alternatiavely:
MyClass myClass = new MyClass(); // runtime exception. 

【讨论】:

  • 这是初始化静态字段的方式,但不是将外部数据传递给静态构造函数,因为至少在 NET 4 中,静态构造函数代码在任何静态方法代码之前执行,并且在任何静态方法代码之前执行字段初始化。
  • 您的评论不准确 - “类的静态字段变量初始化器对应于一系列赋值,它们按照它们在类声明中出现的文本顺序执行。如果静态构造函数 (第 10.11 节)存在于类中,静态字段初始化器的执行发生在执行该静态构造函数之前。否则,静态字段初始化器在第一次使用该类的静态字段之前在与实现相关的时间执行。 "说在:msdn.microsoft.com/en-us/library/aa645758(v=vs.71).aspx
【解决方案2】:

这可能是对...工厂方法的调用!

class Foo 
{ 
  private int bar; 
  private static Foo _foo;

  private Foo() {}

  static Foo Create(int initialBar) 
  { 
    _foo = new Foo();
    _foo.bar = initialBar; 
    return _foo;
  } 

  private int quux; 
  public void Fn1() {} 
} 

您可能需要检查“bar”是否已适当初始化(或未初始化)。

【讨论】:

  • 这是通过将initialBar 参数传递给实例构造函数无法实现的?
  • 在这个例子中,什么都没有。但这确实解决了他的问题,在不了解他的具体情况的情况下,这是我能做的最好的事情。
  • @AlfredBr:从静态方法访问实例字段 _foo 是不可能的,并且不可能从 Foo 的实例访问静态字段“bar”,因为您的代码尝试。我完全不明白你的解决方案。
【解决方案3】:

您不能将参数传递给静态构造函数,但您可以将参数传递给类本身 - 通过泛型类型参数。

这个想法有点疯狂,不过,我还是把它扔掉。

使类成为泛型(使用将提供参数类型的 TypeParam)并在其上放置泛型约束(代码示例中的详细信息),然后派生一个新的参数类型,其中包含可用于读取所需内容的虚数参数值。

//base parameter type - provides the 'anchor' for our generic constraint later, 
//as well as a nice, strong-typed access to our param values.
public class StaticParameterBase
{
  public abstract string ParameterString{ get; }
  public abstract MyComplexType ParameterComplex { get; }
}

//note the use of the new() generic constraint so we know we can confidently create
//an instance of the type.
public class MyType<TParameter> where TParameter:StaticParameterBase, new()
{
  //local copies of parameter values.  Could also simply cache an instance of
  //TParameter and wrap around that. 
  private static string ParameterString { get; set; }
  private static MyComplexType ParameterComplex { get; set; }

  static MyType()
  {
    var myParams = new TParameter();
    ParameterString = myParams.ParameterString;
    ParameterComplex = myParams.ParameterComplex;
  }
}

//e.g, a parameter type could be like this:
public class MyCustomParameterType : StaticParameterBase
{ 
  public override string ParameterString { get { return "Hello crazy world!"; } }
  public override MyComplexType { get {
      //or wherever this object would actually be obtained from.
      return new MyComplexType() { /*initializers etc */ };
    }
  }
}

//you can also now derive from MyType<>, specialising for your desired parameter type
//so you can hide the generic bit in the future (there will be limits to this one's
//usefulness - especially if new constructors are added to MyType<>, as they will 
//have to be mirrored on this type as well).
public class MyType2 : MyType<MyCustomParameterType> { }

//then you'd use the type like this:
public static void main()
{
  var instance = new MyType<MyCustomParameterType>();
  //or this:
  var instance2 = new MyType2();
}

我确实考虑过将自定义类型属性应用于类型参数的解决方案,但这很容易成为更好的方法。但是,您现在将始终使用泛型参数类型来使用您的类(除非您可以使用派生+专业化技巧)- 可能对您的喜好来说太笨拙了。

我也更喜欢这里介绍的其他解决方案,因为它不需要为静态初始化创建任何解决方法 - 您仍然可以使用 .Net 的单次初始化保证。

警告 - 你应该检查你的结构吗?

所有这一切 - 请记住,因为你只能参数化静态一次(或者在这种情况下,每个唯一参数化的静态泛型) - 我会问自己为什么不只是提取获取参数的代码给到静态,并将其放在静态构造函数中?这样你就不必求助于这样的奇怪模式了!

【讨论】:

  • @AlfredBr - 很酷,也许有一天会有用!但不幸的是,它提出了这样的代码,有时让我很难让我的一些组件被团队中的任何人接受,而不是最核心的程序员! c'est la vie!
  • @AndrasZoltan:您的解决方案有效并且已经完成了五月天!!!今天是您的解决方案对我有用的日子。正如您所说,这有点疯狂,但它是一种将外部数据传递给静态构造函数的方法。谢谢
猜你喜欢
  • 2020-05-25
  • 2020-04-20
  • 2013-12-23
  • 2016-03-17
  • 1970-01-01
  • 2019-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多