似乎没想到一个好头衔,我的道歉。随意将其改为更合适的东西;我很感激。
我在这里处于一个不寻常的位置(或者可能不那么不寻常)。我有一个基类型,从中可以分支许多类型,这些类型扩展了它的功能但仍保持相当一致。其中一些或多或少会重复,但以不同的方式呈现数据。它们都可以以相同的方式进行管理,所以我决定创建一个“合并”类,它将采用两个或更多这些对象并允许同时控制它们,但我已经使用了使用反射。如果我要重新定义基类的所有成员并简单地重定向所有sets / gets / etc,那么它只是简单的错误,因为如果我正在“合并”类型的基类是不断变化,合并阶级也必须改变。
但这会导致我认为可以避免的性能成本。性能不仅来自反射,还来自反射过程中可预测的装箱/拆箱。
这是我正在做的一个伪代码示例:
class SomeBase
{
public virtual bool SomeBool { get; set; }
}
class SomeDerived : SomeBase
{
// ... extends SomeBase
}
class SomeMerger
{
private SomeBase[] collection;
public SomeMerger(SomeBase[] collection)
{
this.collection = collection;
}
public void SetProperty(string propertyName, object value)
{
for (int i = 0; i < this.collection.Length; i++)
{
PropertyInfo pi = collection[i].GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
if (pi != null)
pi.SetValue(collection[i], value, null);
}
}
// .. etc
}
现在,我喜欢能够做的就是访问成员,好像它们是合并类中的单个实体一样(例如“SomeMergerObject.SomeBool = true”会设置所有它合并为true的所有对象中的SomeBool属性,使语法更自然)。但是,我能看到这样做的唯一方法是重新定义基类的所有方法和属性,并将调用重定向到它们(我认为这不会被认为是正确的)。是否有更清洁/更好的方法来实现这一目标?
很抱歉,如果我在解释这个问题上表现不佳。大喊大叫如果你感到困惑,我会试着澄清一下。 :)
修改
我想我需要澄清一下。当我说“我有这种基本类型等”时,我认为我误导了 - 实现是现实的,而不是我的,所有我试图做的就是让它变得更容易与...合作。我没有为几个对象设置基本属性,而是在可见状态(例如)等区域中共享,我认为这将是一个很好的功能(尽管是一个微不足道的功能,而且工作量超过了它的价值......但出于好奇心的考虑,为什么不探索这个想法?)使一组对象表现为一个。这甚至没有接近一个问题,只是一个我觉得要调情的改进想法。
我并不是在暗示“一种新的语言功能”,而我的问题的基调是是否有办法实现这一目标,这是一种干净正确的方式。我想我的询问非常糟糕,抱歉。
答案 0 :(得分:4)
听起来你无缘无故地创造了维护噩梦。你的问题并不是那么糟糕,你必须发明基本上是一种新的语言特征。
除此之外,如果您有一组仅在它们如何呈现信息方面有所不同的类型,那么您可以使用除继承之外的其他机制来打破公共代码。例如,您可以将委托传递给他们的“渲染”方法,或者使用策略模式。
答案 1 :(得分:1)
如果我正确解释了问题,请使用the code from here:
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
public interface ISomeInterface {
void SetSomeBool(bool value);
}
class SomeBase : ISomeInterface {
public virtual bool SomeBool { get; set; }
void ISomeInterface.SetSomeBool(bool value) { SomeBool = value; }
}
class SomeDerived : SomeBase {
// ... extends SomeBase
}
static class Program {
static void Main() {
var item1 = new SomeBase();
var item2 = new SomeDerived();
var items = new List<ISomeInterface> { item1, item2};
ISomeInterface group = GroupGenerator.Create(items);
group.SetSomeBool(true);
Console.WriteLine(item1.SomeBool); // true
Console.WriteLine(item2.SomeBool); // true
group.SetSomeBool(false);
Console.WriteLine(item1.SomeBool); // false
Console.WriteLine(item2.SomeBool); // false
}
}
请注意,它也适用于属性,但get
必须抛出异常(set
适用于所有)。出于这个原因,我更喜欢显式方法方法(接口上没有get
)。它也可能只是一个set
属性,但它们真的罕见:
public interface ISomeInterface
{
bool SomeBool { set; }
}
class SomeBase : ISomeInterface
{
public virtual bool SomeBool { get; set; }
}
class SomeDerived : SomeBase
{
// ... extends SomeBase
}
static class Program
{
static void Main()
{
var item1 = new SomeBase();
var item2 = new SomeDerived();
var items = new List<ISomeInterface> { item1, item2};
ISomeInterface group = GroupGenerator.Create(items);
group.SomeBool = true;
Console.WriteLine(item1.SomeBool); // true
Console.WriteLine(item2.SomeBool); // true
group.SomeBool = false;
Console.WriteLine(item1.SomeBool); // false
Console.WriteLine(item2.SomeBool); // false
}
}
答案 2 :(得分:0)
好像你在这里走了一条奇怪的道路。如果你在编译时不知道你正在处理什么类型,你有来使用反射。
但是,您可以在.net 4.0中使用新的动态关键字,并让您的类实现IDynamicMetaObjectProvider以将调用站点检查推迟到运行时。
答案 3 :(得分:0)
此代码使用来自.NET 4的ConcurrentDictionary<TKey, TValue>
,但您可以使用Dictionary<TKey, TValue>
编写它,并使其不是线程安全的或使用粗锁定(lock
语句)并牺牲一点表现。
public static class DynamicObjects
{
private static readonly ConcurrentDictionary<Type, ConcurrentDictionary<string, Action<object, object>>> _setters
= new ConcurrentDictionary<Type, ConcurrentDictionary<string, Action<object, object>>>();
public static void SetProperty(object instance, string property, object value)
{
if (instance == null)
throw new ArgumentNullException("instance");
if (property == null)
throw new ArgumentNullException("property");
if (property.Length == 0)
throw new ArgumentException("The property name cannot be empty.", "property");
Type type = instance.GetType();
var settersForType = _setters.GetOrAdd(type, CreateDictionaryForType);
var setter = settersForType.GetOrAdd(property, (obj, newValue) => CreateSetterForProperty(type, property));
setter(instance, value);
}
private static ConcurrentDictionary<string, Action<object, object>> CreateDictionaryForType(Type type)
{
return new ConcurrentDictionary<string, Action<object, object>>();
}
private static Action<object, object> CreateSetterForProperty(Type type, string property)
{
var propertyInfo = type.GetProperty(property);
if (propertyInfo == null)
return (o, v) => ThrowInvalidPropertyException(type, property);
var setterMethod = propertyInfo.GetSetMethod();
if (setterMethod == null)
return (o, v) => ThrowReadOnlyPropertyException(type, property);
ParameterExpression instance = Expression.Parameter(typeof(object), "instance");
ParameterExpression value = Expression.Parameter(typeof(object), "value");
Expression<Action<object, object>> expression =
Expression.Lambda<Action<object, object>>(
Expression.Call(instance, setterMethod, Expression.Convert(value, propertyInfo.PropertyType)),
instance,
value);
return expression.Compile();
}
private static void ThrowInvalidPropertyException(Type type, string propertyName)
{
throw new InvalidOperationException("The type '" + type.FullName + "' does not have a publicly accessible property '" + propertyName + "'.");
}
private static void ThrowReadOnlyPropertyException(Type type, string propertyName)
{
throw new InvalidOperationException("The type '" + type.FullName + "' does not have a publicly visible setter for the '" + propertyName + "' property.");
}
}