用于多个类的C#泛型方法
本文关键字:泛型方法 用于 | 更新日期: 2023-09-27 18:28:17
我试图寻找解决方案,但我的问题是我甚至不知道该使用什么术语。泛型、委托、LINQ、反射和抽象思想可能是解决方案的一部分,但我的";谷歌傅"没有找到正确的答案。
问题:我有多个类(ClassA
、ClassB
、ClassC
),它们都具有相同的2-3属性DoThisA
、DoThisB
、DoThisC
。
代码的工作方式是,当我处理每个类时,我总是希望执行相同的代码来设置DoThisA
、DoThisB
和DoThisC
。
例如,为了简化,逻辑将始终是:
{some computations to set string currentValueImProcessing to something}
if (xyz) [ClassA|B|C].DoThisA = currentValueImProcessing
else [ClassA|B|C].DoThisB = currentValueImProcessing
我不想一遍又一遍地写同样的语句,那么我如何将对类(a,B,C)的引用发送到一个方法来执行逻辑呢?
如果写得正确,ClassA
、ClassB
和ClassC
中的每一个都会实现一些泛型类,我可以使用它,但我不能。每个类都是独立的,但具有相同的命名属性。
有关于概念/代码的指导吗?
谢谢!
为您的属性创建一个接口:
internal interface IDoThis
{
public string DoThisA { get; set; }
public string DoThisB { get; set; }
public string DoThisC { get; set; }
}
然后,让你的类实现它:
public class ClassA : IDoThis
{
public string DoThisA { get; set; }
public string DoThisB { get; set; }
public string DoThisC { get; set; }
}
public class ClassB : IDoThis
{
// Same properties
}
public class ClassC : IDoThis
{
// Same properties
}
这样,你就可以在某个地方创建一个静态初始化器方法:
internal static class MyClassesExtensions
{
public static void InitTheStuff(this IDoThis obj)
{
// Do something here, for example:
if (String.IsNullOrEmpty(obj.DoThisA))
obj.DoThisA = "foo";
else
obj.DoThisB = obj.DoThisC;
}
}
然后您可以在ClassA
、ClassB
和ClassC
中的任意位置调用this.InitTheStuff()
。
您可以使用反射,也可以使用动态(动态将为您使用反射)
dynamic obj = new ClassA();
obj.DoTHisA();
是如何使用动态
我假设您谈论的是要实例化的类。如果DoThisA、B、C是静态方法,则必须使用反射
注意-如果您可以更改类,那么按照其他人的建议添加一个接口,甚至添加一个通用基类
反射像这个
var type = obj.GetType(); // obj is ClassX object
var method = type.GetMethod("DoTHisA");
method.Invoke(obj);
我还没有检查过这一点,所以语法可能有点错误,但这是反射方法调用的基本机制。如果有多个方法具有相同的名称,如果这些方法带有参数等
至少有四个选项可供选择,甚至更多。
- 创建一个接口,该接口由您的所有类实现,并包含通用方法
- 创建一个基类,所有类都从中继承。然后可以在基类中实现通用功能。如果实现因类而异,但您可以为方法定义公共签名,则使基类成为公共函数抽象。然后,您可以在每个类中实现实际的功能
- 在@pm100的解决方案中使用动态对象
- 使用反射访问通用功能
作为指导方法1。和2。是首选,因为它们允许在编译时检查代码。但是,如果您无法控制包含通用功能的类,例如,您无权访问源代码,或者您被允许对代码进行更改,则可以使用其他两种方法。
如果你问我更喜欢这两种,我想我会选3种。超过4。但这是个人偏好。
您谈论的是继承问题。
对于您的任务,您需要一个具有通用属性的抽象基类:
public abstract class Base
{
public bool DoThisA { get; set; }
public bool DoThisB { get; set; }
}
和子类:
public class A : Base { }
public class B : Base { }
public class C : Base { }
之后,您可以创建一个方法,该方法将接受类型为Base
的对象
public void Do(Base b, bool xyz, bool currentValueImProcessing)
{
if (xyz)
{
b.DoThisA = currentValueImProcessing;
}
else
{
b.DoThisB = currentValueImProcessing;
}
}
这里已经提供了很多方法,所以为了完整性。。。以下是一些运行时代码生成:
public class ClassA
{
public string DoThisA { get; set; }
public int DoThisB { get; set; }
public bool DoThisC { get; set; }
public void Init()
{
// You can call this from anywhere, even from an unrelated class
MyClassInitializer<ClassA>.Init(this);
}
}
public static class MyClassInitializer<T>
{
// Create the getters/setters you need, and make sure they're static.
private static readonly Func<T, string> _getA = BuildGetter<string>("DoThisA");
private static readonly Action<T, string> _setA = BuildSetter<string>("DoThisA");
private static readonly Func<T, int> _getB = BuildGetter<int>("DoThisB");
private static readonly Action<T, int> _setB = BuildSetter<int>("DoThisB");
private static readonly Func<T, bool> _getC = BuildGetter<bool>("DoThisC");
private static readonly Action<T, bool> _setC = BuildSetter<bool>("DoThisC");
private static Func<T, TValue> BuildGetter<TValue>(string name)
{
var obj = Expression.Parameter(typeof(T));
return Expression.Lambda<Func<T, TValue>>(Expression.Property(obj, name), obj).Compile();
}
private static Action<T, TValue> BuildSetter<TValue>(string name)
{
var obj = Expression.Parameter(typeof(T));
var value = Expression.Parameter(typeof(TValue));
return Expression.Lambda<Action<T, TValue>>(Expression.Assign(Expression.Property(obj, name), value), obj, value).Compile();
}
public static void Init(T obj)
{
// Here's your custom initialization method
if (_getA(obj) == "Foo")
_setB(obj, 42);
else
_setC(obj, true);
}
}
不一定是最容易掌握的,但这应该比使用dynamic
或反射快得多。也就是说,如果你不需要速度,坚持使用dynamic
,因为它更容易。