C#在实例化后更改通用对象?

时间:2012-03-06 19:53:36

标签: c# generics

在SomeClass实例化后,是否可以将TEntity更改为NewEntity?

例如,采用此类定义:

public class SomeClass<TEntity> where TEntity : class
{
   public void ChangeSet<NewEntity>()
    {
        TEntity = NewEntity;//not valid
    }
 }

实例化如下:

var sc = new SomeClass<SomeEntity>();

我该如何做到这一点?

sc.ChangeSet<NewEntity>();

4 个答案:

答案 0 :(得分:2)

  

在SomeClass实例化后,是否可以将TEntity更改为NewEntity?

,这是不可能的。 CLR如何知道如何将值从TEntity映射到SomeEntity?它们是不同的类型。这就像要求你的杂货商把苹果变成橙子一样。

不推荐下面的代码。您需要担心的问题很多,而且容易出错。我提供它作为你要求CLR做的一个例子。

SomeClass<Foo> fooClass = new SomeClass<Foo>():
//do stuff to fooClass
SomeClass<Baz> = fooClass.ChangeSet<Baz>();

public class SomeClass<T> where T : class
{
    public SomeClass<K> ChangeSet<K>() where K:class
    {
       var changed = new SomeClass<K>();
       //manually map the properties over
       //but how do you know that Foo.PropertyA fits into Baz.PropetyZed?
       //what happens if Foo.A has a string length of 100, but Baz.A has a max length of 50? What do you do?
       //What id Foo.ID is an INT and Baz.ID is a GUID?
       return changed;
    }
}

答案 1 :(得分:2)

泛型用于在编译时强制执行类型安全。最好将new SomeClass<SomeEntity>()视为实际的类本身。实际上,它是作为一个类编译的。您可以根据以下泛型类中的静态字段示例看到:

public class GenericTest<T> where T : class   
{
    public static int StaticIntField { get; set; }

    public GenericTest(int setGenericIntField)
    {
        StaticIntField = setGenericIntField;
    }
}

用这个测试:

var stringTest =new  GenericTest<string>(1);
var objectTest = new GenericTest<object>(2);

System.Diagnostics.Debug.Print(GenericTest<string>.StaticIntField.ToString()); //<-- prints 1
System.Diagnostics.Debug.Print(GenericTest<object>.StaticIntField.ToString()); //<-- prints 2
System.Diagnostics.Debug.Print(GenericTest<Control>.StaticIntField.ToString()); //<-- prints 0 because we haven't created an instance of this type yet

答案 2 :(得分:2)

您是否尝试将一组TEntity对象转换为一组NewEntity对象?如果是这样,那是可能的,但是你还没有找到正确的语法。

  

这就是我追求的大部分内容,是的。你能详细说明吗?

假设您有一个泛型类C<T>,它代表一组T个实例,并且您希望将其转换为泛型类C<U>的实例;一组U个实例。您无法更改C<T>实例的类型,但可以创建类型为C<U>的新对象。签名将是:

public class C<T>
{
    public C<U> Convert<U>()
    {
        C<U> result = new C<U>();
        // populate the result somehow
        return result;
    }
}

为了提供实现,进一步假设将一组T实例转换为一组U实例的机制是将每个T转换为{{{ 1}}。您可以提供U来实现转化。我们还将为Func<T, U>提供一个构造函数,该构造函数需要C<T>来填充集合:

IEnumerable<T>

我们可以按原样使用它,尽管在这一点上我们所做的只是将linq的一个笨拙的包装器放到了对象上:

public class C<T>
{
    IEnumerable<T> _items;
    public C(IEnumerable<T> items)
    {
        _items = items;
    }
    public C<U> Convert<U>(Func<T, U> convertElement)
    {
        return new C<U>(_items.Select(convertElement));
    }
}

其中一些可能与您的需求不相符;如果是这样,发表评论,我会尝试相应调整。

答案 3 :(得分:1)

泛型参数是类的编译时模板。因此,当您SomeClass<TEntity>实例化为SomeClass<int>时,您或多或少会告诉编译器您的类型为“某些类应用于int”。

现在,在运行时,您希望能够将“SomeClass应用于int”重新定义为“SomeClass应用于{whatever}”。但是,“应用于部分”需要在编译时指定,因此您无法执行此操作。

想到它的另一种方式是想象一下这是否实施了。例如,想象一下int上的ChangeSet<T>方法,有人可能会突然将你的int变成字符串或对象或Foos。请注意,不要强制转换它们,而是在运行时更改int的类定义。糟糕!