【问题标题】:C# How to access an ambiguously typed object (e.g. 'var') as a specifically typed object (e.g. 'Form')C#如何访问一个模糊类型的对象(例如'var')作为一个特定类型的对象(例如'Form')
【发布时间】:2016-08-09 20:21:54
【问题描述】:

我正在尝试迭代表单列表 (Mdichildren),并比较列表中特定表单的值。然而,使用 var 来包含任何类型的 Form 使得使用 form.Value 可能是特定于给定表单的困难。

foreach (var oven in Ovens) // list of objects
{
    foreach (var form in this.Mdichildren) // contains multiple form types
    {
        if (form is Form_OvenControl)
        {
            if (oven.Id == form.ovenId)
            {
                // this fails because form.ovenId is treated like var, not like Form_OvenControl
            }
        }
        else if (form is Form_Instructions)
        {
            // do something with different type of form
        }
    }
}

我知道我可以转换该值并创建该类型表单的新变量,但我想通过列表中的引用来使用该对象。我敢肯定我可以想出一个 hacky 方法,但我敢肯定有一种巧妙的方法可以做一些事情(不那么非法,但是),比如:

(Form_OvenControl)form.formSpecificValue = 0;

编辑: 正如下面所指出的,我可以简单地执行以下操作:

if (form is Form_OvenControl)
{
    var ovenform = form as Form_OvenControl;
    if (oven.Id == ovenform.ovenId)
    {

    }
}

演员表仍然会引用我要更改的列表中的项目。

我刚刚想到有一种方法可以将表单用作 Form_OvenControl 并基本上在一行中访问其中的变量。

【问题讨论】:

  • 如果他的属性在基类中不存在,那么你将不得不进行强制转换。并且尽可能不要使用 var 。使代码更难阅读
  • 旁注:您对var 有一些误解 - 请务必阅读stackoverflow.com/questions/41479/use-of-var-keyword-in-c-sharp
  • 你说的是什么意思,但是我想在列表中通过引用来使用对象?即使您创建一个新变量并对其进行强制转换,它仍然会引用列表中的Form。
  • @ChrisDunaway,谢谢。从本质上讲,我想我对“如果我更改一个值,创建一个新变量并从列表中的对象进行转换是否仍然引用列表中的项目”这个问题的措辞不佳?谢谢你的直接。

标签: c# winforms visual-studio .net-4.0


【解决方案1】:
  1. 它不是“类型模糊的对象”。那有什么意思?你是从哪里得到的?

    这是一个强类型变量,其类型由编译器推断确定。在这种情况下可能是Form。

    在编译器可以从上下文推断类型的情况下,这只是节省打字和视觉混乱的简写:

    //  l is of type List<int> b/c duh
    var l = new List<int>();
    
    //  n must be int, because l is List<int>
    foreach (var n in l)
    {
    }
    

    该代码将执行与该代码完全相同的操作:

    List<int> l = new List<int>();
    
    foreach (int n in l)
    {
    }
    
  2. 我知道我可以转换该值并创建该类型表单的新变量,但我想通过列表中的引用来使用该对象

    只需将其转换为需要的类型:

    if (form is Form_OvenControl)
    {
        var ovenform = form as Form_OvenControl;
        if (oven.Id == ovenform.ovenId)
        {
        }
    }
    else if (form is Form_Instructions)
    {
        var instform = form as Form_Instructions;
        // do something with different type of form
    }
    

更新

在 C#7 中...

    if (form is Form_OvenControl ovenform)
    {
        if (oven.Id == ovenform.ovenId)
        {
        }
    }
    else if (form is Form_Instructions instform)
    {
        // do something with instform
    }

【讨论】:

  • 您正确的浇铸到混凝土类型是一种可能的解决方案。但我认为编写那些 if -> elseif -> elseif -> elseif -> else 结构是不好的做法。如果添加新的 Form 类型,则必须编写新的 if 块。
  • @whymatter 完全正确。但这会让他暂时动起来。而且我认为 Form 不是他的类——他必须定义一个通用的中间子类。
【解决方案2】:

您可以在每个继承者的overridden 类Form 上定义virtual method。虚拟方法的实现可以处理你需要的任何东西。你可以传递任何你需要的参数。

编辑:使用 virtual 以防您必须实例化 From。这对于抽象类是不可能的。

class Program {
    static void Main(string[] args) {
        Form big = new FormBig();
        Form small = new FormSmall();

        big.DoJob(null); // FormBig
        small.DoJob(null); // FormSmall

        Console.ReadLine();
    }
}

class Form {
    public virtual void DoJob(object parametersYouNeed) {
        throw new NotImplementedException("use only on inheritor");
    }
}

class FormBig : Form {
    public override void DoJob(object parametersYouNeed) {
        Console.WriteLine("FormBig");
    }
}

class FormSmall : Form {
    public override void DoJob(object parametersYouNeed) {
        Console.WriteLine("FormSmall");
    }
}

每当您添加新的 Form 类型时,您只需实现方法 DoJob 并且您的代码无需修改即可运行。

这也符合 S.​​O.L.I.D 的 Open/Closed 原则!


编辑:如果您不能对 Form 类进行修改

class Program {
    static void Main(string[] args) {
        FormMiddleMan big = new FormBig();
        FormMiddleMan small = new FormSmall();

        big.DoJob(null); // FormBig
        small.DoJob(null); // FormSmall

        Console.ReadLine();
    }
}

class Form {

}

abstract class FormMiddleMan : Form {
    public abstract void DoJob(object parametersYouNeed);
}

class FormBig : FormMiddleMan {
    public override void DoJob(object parametersYouNeed) {
        Console.WriteLine("FormBig");
    }
}

class FormSmall : FormMiddleMan {
    public override void DoJob(object parametersYouNeed) {
        Console.WriteLine("FormSmall");
    }
}

定义一个继承自Form 类的FormMiddleMan 类。它定义了DoJob 方法。您的每个具体类型都继承自 FormMiddleMan,并且必须实现 DoJob 方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多