C# 使包装类的扩展方法/构造函数成为泛型
在一个服务(我无法更改)中,我有两个对象类C# 使包装类的扩展方法/构造函数成为泛型,c#,wpf,generics,wrapper,C#,Wpf,Generics,Wrapper,在一个服务(我无法更改)中,我有两个对象类Bar和Baz,它们的属性基本相似(但遗憾的是,它们不是从同一个基类派生的,也不是从同一个接口继承的……是的——愚蠢),以及与其相对BarQux和BazQux属性相关的依赖类: public class Bar public class Baz { { public int ID { get; set; }
Bar
和Baz
,它们的属性基本相似(但遗憾的是,它们不是从同一个基类派生的,也不是从同一个接口继承的……是的——愚蠢),以及与其相对BarQux
和BazQux
属性相关的依赖类:
public class Bar public class Baz
{ {
public int ID { get; set; } public int ID { get; set; }
public bool Active { get; set; } public bool Active { get; set; }
public int BarQux { get; set; } public int BazQux { get; set; }
... ...
} }
public class Qux
{
public int ID { get; set; } // Corresponds to BarQux and BazQux
public string Name { get; set; }
}
在WPF屏幕中,我将每种类型的列表(Baz
和Bar
)绑定到两个独立的列表视图。我需要每个都有一个额外的选中的复选框列。为此,我创建了一个包装类,其中包含公共属性、附加的Selected
属性以及每个属性的构造函数:
public class Foo
{
public Foo(Bar bar, Qux qux)
{
this.Active = bar.Active;
this.FooQux = string.Format("{0} - {1}", qux.ID, qux.Name);
...
}
public Foo(Baz baz, Qux qux)
{
this.Active = baz.Active;
this.FooQux = string.Format("{0} - {1}", qux.ID, qux.Name);
...
}
public bool Selected { get; set; }
public int ID { get; set; }
public bool Active { get; set; }
public string FooQux { get; set; }
...
}
为了将类Baz
和Bar
的每个集合转换为Foo
的集合,我创建了以下扩展方法:
public static List<Foo> ToFoo(this IEnumerable<Bar> bars, IEnumerable<Qux> quxs)
{
List<Foo> foos = new List<Foo>();
foreach (Bar bar in bars)
{
Foo foo = new Foo(bar, quxs.Single(qux => qux.ID == bar.BarQux));
foos.Add(foo);
}
return foos;
}
public static List<Foo> ToFoo(this IEnumerable<Baz> bazs, IEnumerable<Qux> quxs)
{
List<Foo> foos = new List<Foo>();
foreach (Baz baz in bazs)
{
Foo foo = new Foo(baz, quxs.Single(qux => qux.ID == baz.BazQux));
foos.Add(foo);
}
return foos;
}
更改构造函数以接收整个Qux
对象集合,并在其中执行quxs.Single(Qux=>Qux.ID==object.ObjectQux)
逻辑。然后将扩展方法变成一个泛型方法,如下所示
public static List<Foo> ToFoo<T>(this IEnumerable<T> objCollection, IEnumerable<Qux> quxs)
{
List<Foo> foos = new List<Foo>();
foreach (T obj in objCollection)
{
Foo foo = new Foo(obj, quxs); // The best overloaded method... has some invalid arguments.
foos.Add(foo);
}
return foos;
}
公共静态列表ToFoo(此IEnumerable对象集合,IEnumerable QUX)
{
List foos=新列表();
foreach(对象集合中的T对象)
{
Foo Foo=new Foo(obj,quxs);//最好的重载方法…有一些无效参数。
添加(foo);
}
返回foos;
}
1和2的组合?有什么我没想到的吗
如果属性有限,并且列表中的项目数也很少,则可以使用反射
。由于您将在WPF中使用它,我还建议将该进程移动到单独的后台线程
通用Foo
public class Foo<T>
{
public Foo(T obj, Qux qux)
{
//this.Active = obj.Active;
var fooProps = GetType().GetProperties().ToList();
var tProps = typeof(T).GetProperties()
.Where(p =>
{
var w = fooProps.FirstOrDefault(f => f.Name == p.Name);
return w != null;
}).ToList();
foreach (var propertyInfo in tProps)
{
var val = propertyInfo.GetValue(obj);
fooProps.First(e => e.Name == propertyInfo.Name).SetValue(this, val);
}
this.FooQux = string.Format("{0} - {1}", qux.ID, qux.Name);
}
public bool Selected { get; set; }
public int ID { get; set; }
public bool Active { get; set; }
public string FooQux { get; set; }
}
然后您可以调用ToFoo
扩展方法,瞧,您有一个Foo列表
您还可以使用Qux
class的逻辑将Foo转换为非泛型,我看不出这样做有什么好处
如果您坚持使用泛型,您可以在T上执行一些类型检查,如下所示:
public class Foo<T>
{
public Foo(T obj, Qux qux)
{
var baz = obj as Baz;
var bar = obj as Bar;
Active = baz != null && baz.Active || bar != null && bar.Active;
this.FooQux = string.Format("{0} - {1}", qux.ID, qux.Name);
}
public bool Selected { get; set; }
public int ID { get; set; }
public bool Active { get; set; }
public string FooQux { get; set; }
}
公共类Foo
{
公共食品(T obj,Qux Qux)
{
var baz=作为baz的obj;
var bar=obj as bar;
Active=baz!=null&&baz.Active | | bar!=null&&bar.Active;
this.FooQux=string.Format(“{0}-{1}”,qux.ID,qux.Name);
}
已选择公共布尔值{get;set;}
公共int ID{get;set;}
公共bool活动{get;set;}
公共字符串FooQux{get;set;}
}
或:
公共静态列表ToFoo(此IEnumerable对象集合,IEnumerable QUX)
{
List foos=新列表();
foreach(对象集合中的T对象)
{
var baz=作为baz的obj;
var bar=obj as bar;
Foo-Foo=null;
如果(baz!=null)
foo=newfoo(baz,quxs.Single(qux=>qux.ID==baz.BazQux));
如果(bar!=null)
foo=newfoo(bar,quxs.Single(qux=>qux.ID==bar.BarQux));
如果(foo!=null)
添加(foo);
}
返回foos;
}
但这显然并不比您已有的好多少,如果t不是Bar或Baz(未显示),您将不得不执行一些异常处理,这将使您面临潜在的运行时故障。您也可以使用反射,但也可以使用反射
不幸的是,使用C#不可能实现您正在寻找的功能。如果接口是鸭型a-la Golang,则唯一可以避免这种情况的方法是,但事实并非如此。根据Sandesh的建议,最终结果:
public class Foo<T>
{
public Foo() {}
public Foo(T obj, IEnumerable<Qux> quxs, string quxPropName)
{
var fooProps = GetType().GetProperties().ToList();
var tProps = typeof(T).GetProperties()
.Where(p =>
{
var w = fooProps.FirstOrDefault(f => f.Name == p.Name);
return w != null;
}).ToList();
foreach (var propertyInfo in tProps)
{
var val = propertyInfo.GetValue(obj, null);
fooProps.First(e => e.Name == propertyInfo.Name).SetValue(this, val, null);
}
int id = (int)typeof(T).GetProperty(quxPropName).GetValue(obj, null);
Qux qux = quxs.Single(q => q.ID == id);
this.FooQux = string.Format("{0} - {1}", qux.ID, qux.Name);
}
public bool Selected { get; set; }
public int ID { get; set; }
public bool Active { get; set; }
public string FooQux { get; set; }
}
公共类Foo
{
公共Foo(){}
public Foo(T obj,IEnumerable qux,string quxPropName)
{
var fooProps=GetType().GetProperties().ToList();
var tProps=typeof(T).GetProperties()
.其中(p=>
{
var w=fooProps.FirstOrDefault(f=>f.Name==p.Name);
返回w!=null;
}).ToList();
foreach(tProps中的var propertyInfo)
{
var val=propertyInfo.GetValue(obj,null);
fooProps.First(e=>e.Name==propertyInfo.Name).SetValue(this,val,null);
}
int id=(int)typeof(T).GetProperty(quxPropName).GetValue(obj,null);
Qux=Qux.Single(q=>q.ID==ID);
this.FooQux=string.Format(“{0}-{1}”,qux.ID,qux.Name);
}
已选择公共布尔值{get;set;}
公共int ID{get;set;}
公共bool活动{get;set;}
公共字符串FooQux{get;set;}
}
和通用扩展方法:
public static List<Foo<T>> ToFoo<T>(this IEnumerable<T> list, IEnumerable<Qux> quxs, string quxPropName)
{
List<Foo<T>> foos = null;
try
{
foos = list.Select(obj => new Foo<T>(obj, quxs, quxPropName)).ToList();
}
catch
{
foos = new List<Foo<T>>();
}
return foos;
}
公共静态列表ToFoo(此IEnumerable列表、IEnumerable qux、字符串quxPropName)
{
列表foos=null;
尝试
{
foos=list.Select(obj=>newfoo(obj,quxs,quxPropName)).ToList();
}
抓住
{
foos=新列表();
}
返回foos;
}
使用方法:
List<Foo<Bar>> bars = barCollection.ToFoo(quxCollection, "BarQux");
List<Foo<Baz>> bazs = bazCollection.ToFoo(quxCollection, "BazQux");
List bar=barCollection.ToFoo(quxCollection,“BarQux”);
List baz=bazCollection.ToFoo(quxCollection,“BazQux”);
你可能想检查一下,你不能修改文件还是不能修改类?例如,您可以实现一个分部类。但是您必须将原始类更改为分部类。@ScottNimrod我无法修改服务中的任何类或文件,例如栏
、Baz
和类型
类。如果可以的话,我想让前两个继承自基类或接口-这将使我在泛化方面的有限经验更容易实现。这看起来像是一个DTO对象到/从BusinessObject的案例。您可以完全控制businessObject实现,但DTO对象实际上来自“难以”更改的外部服务。我有一个场景,在这个场景中,当我被告知可能会有一些mor时,应用程序开发已经进行了一半
public static List<Foo> ToFoo<T>(this IEnumerable<T> objCollection, IEnumerable<Qux> quxs)
{
List<Foo> foos = new List<Foo>();
foreach (T obj in objCollection)
{
var baz = obj as Baz;
var bar = obj as Bar;
Foo foo = null;
if(baz != null)
foo = new Foo(baz, quxs.Single(qux => qux.ID == baz.BazQux));
if(bar != null)
foo = new Foo(bar, quxs.Single(qux => qux.ID == bar.BarQux));
if(foo != null)
foos.Add(foo);
}
return foos;
}
public class Foo<T>
{
public Foo() {}
public Foo(T obj, IEnumerable<Qux> quxs, string quxPropName)
{
var fooProps = GetType().GetProperties().ToList();
var tProps = typeof(T).GetProperties()
.Where(p =>
{
var w = fooProps.FirstOrDefault(f => f.Name == p.Name);
return w != null;
}).ToList();
foreach (var propertyInfo in tProps)
{
var val = propertyInfo.GetValue(obj, null);
fooProps.First(e => e.Name == propertyInfo.Name).SetValue(this, val, null);
}
int id = (int)typeof(T).GetProperty(quxPropName).GetValue(obj, null);
Qux qux = quxs.Single(q => q.ID == id);
this.FooQux = string.Format("{0} - {1}", qux.ID, qux.Name);
}
public bool Selected { get; set; }
public int ID { get; set; }
public bool Active { get; set; }
public string FooQux { get; set; }
}
public static List<Foo<T>> ToFoo<T>(this IEnumerable<T> list, IEnumerable<Qux> quxs, string quxPropName)
{
List<Foo<T>> foos = null;
try
{
foos = list.Select(obj => new Foo<T>(obj, quxs, quxPropName)).ToList();
}
catch
{
foos = new List<Foo<T>>();
}
return foos;
}
List<Foo<Bar>> bars = barCollection.ToFoo(quxCollection, "BarQux");
List<Foo<Baz>> bazs = bazCollection.ToFoo(quxCollection, "BazQux");