gpt4 book ai didi

c# - 通用设计指南c#;发现我在方法之间不必要地传递对象

转载 作者:太空宇宙 更新时间:2023-11-03 22:49:27 26 4
gpt4 key购买 nike

抱歉,它可能有点含糊,但它已经困扰我好几个星期了。我发现我处理的每个项目最终都犯了我认为是设计错误的错误,并且我很确定有一个更好的方法。

当定义一个从事件源序列化的类时,就像一个简单的 json 文档定义。让我们用各种定义的整数、 bool 值和字符串称它为键类。我有多种使用它的方法,我发现我经常需要通过重载将此类作为对象传递给对象。因此,方法 a 调用方法 b,方法 b 不需要这些对象,但它调用方法 c,而方法 c 确实...在执行这种不良做法时,我将这些“键”对象传递给方法 b,其唯一目的是方法 c 的可访问性。

我可能遗漏了一个主要的 OOP 基础知识 :) 任何指导或阅读将不胜感激,因为我用谷歌搜索了!!

public class Keys
{
public child Detail { get; set; }
}

public class child
{
public string instance { get; set; }
}

//my main entry point
public void FunctionHandler(Keys input, ILambdaContext context)
{
methodA(input)
}

static void methodA(Keys input)
{
//some-other logic or test that doesn't need Keys object/class if (foo==bar) {proceed=true;}
string foo = methodB(input)
}

static string methodB(Keys input)
{
//here i need Keys do do stuff and I return a string in this example
}

最佳答案

你所做的不一定是坏事或错事。请记住,在 C# 中,您实际传递的是引用,而不是对象本身,因此参数传递的开销非常小。

长调用链的主要缺点是程序逻辑可能比需要的更复杂,并且通常存在可维护性问题。

有时您可以使用 C# 类型系统让编译器或运行时选择合适的函数。

当您为两种不同类型重载 method() 而不是定义 methodA()methodB( )。但它们是通过参数类型来区分的,因此您需要不同的 Key 类型,这些类型可能(但不一定)相关:

public class KeyA {/*...*/}
public class KeyB {/*...*/}

void method(KeyA kA) { /* do something with kA */ }
void method(KeyB kB) { /* do something with kB */ }

这是有限的好处;这些函数具有相同的名称只是语法糖,清楚地表明它们服务于相同的目的。

另一种可能更优雅和通用的技术是创建 Key 的继承层次结构,每个“知道”方法 应该做什么。

您需要一个具有虚拟方法 的基类,该方法将被继承类覆盖。通常基础是一个接口(interface),只是声明有一些 method(),各种实现类型实现适合它们的 method()。这是一个有点冗长的示例,它使用虚拟 Output() 方法,以便我们在控制台上看到一些东西。

值得注意的是,每个Key 调用一个OutputterI 的方法,将自身作为参数传递给它;然后输出器类依次回调调用对象的方法。这称为“双重分派(dispatch)”,结合了运行时多态性和编译时函数重载。在编译时,对象及其具体类型是未知的;事实上,它们可以稍后实现(例如,通过发明另一个 Key)。但是每个对象都知道在其回调函数(此处为:GetData())被调用时要做什么。

using System;
using System.Collections.Generic;

namespace DoubleDispatch
{
interface KeyI
{ // They actually delegate that to an outputter
void Output();
}

interface OutputterI
{
void Output(KeyA kA);
void Output(KeyExtra kE);
void Output(KeyI k); // whatever this does.
}

class KeyBase: KeyI
{
protected OutputterI o;

public KeyBase(OutputterI oArg) { o = oArg; }

// This will call Output(KeyI))
public virtual void Output() { o.Output(this); }
}

class KeyA : KeyBase
{
public KeyA(OutputterI oArg) : base(oArg) { }

public string GetAData() { return "KeyA Data"; }

// This will compile to call Output(KeyA kA) because
// we pass this which is known here to be of type KeyA
public override void Output() { o.Output(this); }
}

class KeyExtra : KeyBase
{
public string GetEData() { return "KeyB Data"; }
public KeyExtra(OutputterI oArg) : base(oArg) { }

/** Some extra data which needs to be handled during output. */
public string GetExtraInfo() { return "KeyB Extra Data"; }

// This will, as is desired,
// compile to call o.Output(KeyExtra)
public override void Output() { o.Output(this); }
}

class KeyConsolePrinter : OutputterI
{
// Note: No way to print KeyBase.
public void Output(KeyA kA) { Console.WriteLine(kA.GetAData()); }
public void Output(KeyExtra kE)
{
Console.Write(kE.GetEData() + ", ");
Console.WriteLine(kE.GetExtraInfo());
}
// default method for other KeyI
public void Output(KeyI otherKey) { Console.WriteLine("Got an unknown key type"); }

}
// similar for class KeyScreenDisplayer{...} etc.

class DoubleDispatch
{
static void Main(string[] args)
{

KeyConsolePrinter kp = new KeyConsolePrinter();

KeyBase b = new KeyBase(kp);
KeyBase a = new KeyA(kp);
KeyBase e = new KeyExtra(kp);

// Uninteresting, direkt case: We know at compile time
// what each object is and could simply call kp.Output(a) etc.
Console.Write("base:\t\t");
b.Output();

Console.Write("KeyA:\t\t");
a.Output();

Console.Write("KeyExtra:\t");
e.Output();

List<KeyI> list = new List<KeyI>() { b, a, e };
Console.WriteLine("\nb,a,e through KeyI:");

// Interesting case: We would normally not know which
// type each element in the vector has. But each type's specific
// Output() method is called -- and we know it must have
// one because that's part of the interface signature.
// Inside each type's Output() method in turn, the correct
// OutputterI::Output() for the given real type was
// chosen at compile time dpending on the type of the respective
// "this"" argument.
foreach (var k in list) { k.Output(); }
}
}
}

示例输出:

base:           Got an unknown key type
KeyA: KeyA Data
KeyExtra: KeyB Data, KeyB Extra Data

b,a,e through KeyI:
Got an unknown key type
KeyA Data
KeyB Data, KeyB Extra Data

关于c# - 通用设计指南c#;发现我在方法之间不必要地传递对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48140006/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com