我应该如何用 C#方法重载实现这样的目的

2022-08-06 02:44:35 +08:00
 wdc63

我有一系列类型不定的对象,同时为每个对象提供了相应的方法,这个对象由一个方法在实时运算中提供,不确定,请问 C#中有没有方法如何利用重载或其他手段来实现对象被输入给相应的方法,例如实现下面这种,但是当然下面这种写法会报错。

不太想用判断,写起来太繁琐了。

    private static void test(string str)
    {
        Console.WriteLine(str);
    }

    private static void test(int i)
    {
        Console.WriteLine(i);
    }

    private static void Main(string[] args)
    {
        var a = new List<object>() { 123, "asd" };
        test(a[0]);
        test(a[1]);
    }
1942 次点击
所在节点    C#
23 条回复
hez2010
2022-08-07 23:51:48 +08:00
@Zhuzhuchenyan
> 大概是普通反射的 30 倍快

以前可能是这样,但这一点在 .NET 7 上不成立了
neilq
2022-08-08 15:47:18 +08:00
// 简单用设计模式包裹了一下,工厂+策略,没测试,可以复制到 ide 方便看

public class HandlerKeyAttribute : Attribute
{
public HandlerKeyAttribute(string name)
{
Name = name;
}

public string Name { get; set; }
}

[HandlerKey(nameof(ArgA))]
class ArgA
{
}

[HandlerKey(nameof(ArgB))]
class ArgB
{
}

public class Message
{
public object Param { get; set; }
}

public interface IHandler
{
Task Handle(Message msg);
}

[HandlerKey(nameof(ArgA))]
public class HandlerA : IHandler
{
public Task Handle(Message msg)
{
throw new NotImplementedException();
}
}

[HandlerKey(nameof(ArgB))]
public class HandlerB : IHandler
{
public Task Handle(Message msg)
{
throw new NotImplementedException();
}
}

public class HandlerFactory
{
private static readonly Dictionary<string, Type> _handlerTypes = new();

static HandlerFactory()
{
var handlerTypeInfos = Assembly.GetAssembly(typeof(Program)).DefinedTypes
.Where(x => x.IsClass
&& !x.IsAbstract
&& x.GetInterfaces().Any(i => i == typeof(IHandler)))
.ToList();
foreach (var type in handlerTypeInfos)
{
var attr = type.GetCustomAttribute<HandlerKeyAttribute>();
if (attr != null && !string.IsNullOrEmpty(attr.Name))
{
try
{
_handlerTypes.Add(attr.Name, type);
}
catch (Exception)
{
// 当心 key name 重复
}
}
}
}

public IHandler CreateHandler(object arg)
{
//简单用 attribute 匹配 arg 与 handler 类型,具体场景也可以用其他特征(如直接用对象名称)匹配,也可以结合正则、startsWith 等方式匹配
var attr = arg.GetType().GetCustomAttribute<HandlerKeyAttribute>();

if (attr == null || string.IsNullOrEmpty(attr.Name)) return null;

if (!_handlerTypes.TryGetValue(attr.Name, out var handlerType))
return null;

// 部分框架里可以利用 ioc container 创建, 如 return _serviceProvider.GetRequiredService(handlerType) as IMqttMessageHandler;
// 部分场景也可以预创建对象,如_handlerTypes 类型改成 Dictionary<string, IHandler> handlers, 直接取拿出来用: return handlers[attr.name]
return (IHandler)Activator.CreateInstance(handlerType);

}
}

public class Program
{
private static void Main(string[] args)
{
var objects = new List<object> { new ArgA(), new ArgB() };
var factory = new HandlerFactory();
foreach (var arg in objects)
{
var handler= factory.CreateHandler(arg);
handler.Handle(new Message { Param = arg });
}
}
}
wdc63
2022-08-09 00:24:43 +08:00
@neilq 谢谢大佬,太有帮助了,这两天我自己想着弄了个委托的方法。我再测试下您的模式。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/871010

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX